X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libopenjpeg%2Fj2k.c;h=509b627fadb44f3a91b2de1b79e70898884a83a3;hb=71e0106846294256faa3df75429e0a9ecd163233;hp=19b4d2b4dc9aabed8d43d944dda01c37b38f322a;hpb=455f675806670fb095b824a2cdb99350a63eeefc;p=openjpeg.git diff --git a/libopenjpeg/j2k.c b/libopenjpeg/j2k.c index 19b4d2b4..509b627f 100644 --- a/libopenjpeg/j2k.c +++ b/libopenjpeg/j2k.c @@ -8,7 +8,7 @@ * Copyright (c) 2008, Jerome Fimes, Communications & Systemes * Copyright (c) 2006-2007, Parvatha Elangovan * Copyright (c) 2010-2011, Kaori Hagihara - * Copyright (c) 2011, Mickael Savinaud, Communications & Systemes + * Copyright (c) 2011-2012, Mickael Savinaud, Communications & Systemes * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -49,10 +49,22 @@ void j2k_setup_header_reading (opj_j2k_v2_t *p_j2k); /** * The read header procedure. */ -opj_bool j2k_read_header_procedure( - opj_j2k_v2_t *p_j2k, - struct opj_stream_private *p_stream, - struct opj_event_mgr * p_manager); +static opj_bool j2k_read_header_procedure( opj_j2k_v2_t *p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager); + +/** + * The default encoding validation procedure without any extension. + * + * @param p_j2k the jpeg2000 codec to validate. + * @param p_stream the input stream to validate. + * @param p_manager the user event manager. + * + * @return true if the parameters are correct. + */ +static opj_bool j2k_encoding_validation ( opj_j2k_v2_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ); /** * The default decoding validation procedure without any extension. @@ -63,11 +75,15 @@ opj_bool j2k_read_header_procedure( * * @return true if the parameters are correct. */ -opj_bool j2k_decoding_validation ( - opj_j2k_v2_t * p_j2k, - opj_stream_private_t *p_stream, - opj_event_mgr_t * p_manager - ); +static opj_bool j2k_decoding_validation ( opj_j2k_v2_t * p_j2k, + opj_stream_private_t *p_stream, + 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. + */ +static void j2k_setup_encoding_validation (opj_j2k_v2_t *p_j2k); /** * Sets up the validation ,i.e. adds the procedures to lauch to make sure the codec parameters @@ -75,39 +91,89 @@ opj_bool j2k_decoding_validation ( */ static void j2k_setup_decoding_validation (opj_j2k_v2_t *p_j2k); +/** + * 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. + */ +static void j2k_setup_end_compress (opj_j2k_v2_t *p_j2k); + +/** + * The mct encoding validation procedure. + * + * @param p_j2k the jpeg2000 codec to validate. + * @param p_stream the input stream to validate. + * @param p_manager the user event manager. + * + * @return true if the parameters are correct. + */ +static opj_bool j2k_mct_validation (opj_j2k_v2_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ); + /** * Builds the tcd decoder to use to decode tile. */ -opj_bool j2k_build_decoder ( - opj_j2k_v2_t * p_j2k, - opj_stream_private_t *p_stream, - opj_event_mgr_t * p_manager - ); +static opj_bool j2k_build_decoder ( opj_j2k_v2_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ); +/** + * Builds the tcd encoder to use to encode tile. + */ +static opj_bool j2k_build_encoder ( opj_j2k_v2_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ); + +/** + * Creates a tile-coder decoder. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_create_tcd( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); /** * Excutes 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. - * @param p_stream the stream to execute the procedures on. + * @param p_j2k the jpeg2000 codec to execute the procedures on. + * @param p_stream the stream to execute the procedures on. * @param p_manager the user manager. * * @return true if all the procedures were successfully executed. */ -static opj_bool j2k_exec ( - opj_j2k_v2_t * p_j2k, - opj_procedure_list_t * p_procedure_list, - opj_stream_private_t *p_stream, - opj_event_mgr_t * p_manager - ); +static opj_bool j2k_exec ( opj_j2k_v2_t * p_j2k, + opj_procedure_list_t * p_procedure_list, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager); + +/** + * Updates the rates of the tcp. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_update_rates( opj_j2k_v2_t *p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ); /** * Copies the decoding tile parameters onto all the tile parameters. * Creates also the tile decoder. */ -opj_bool j2k_copy_default_tcp_and_create_tcd ( opj_j2k_v2_t * p_j2k, - opj_stream_private_t *p_stream, - opj_event_mgr_t * p_manager ); +static opj_bool j2k_copy_default_tcp_and_create_tcd ( opj_j2k_v2_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ); + +/** + * Destroys the memory associated with the decoding of headers. + */ +static opj_bool j2k_destroy_header_memory ( opj_j2k_v2_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ); /** * Reads the lookup table containing all the marker, status and action, and returns the handler associated @@ -125,6 +191,12 @@ static const struct opj_dec_memory_marker_handler * j2k_get_marker_handler (OPJ_ */ static void j2k_tcp_destroy (opj_tcp_v2_t *p_tcp); +/** + * Destroys the data inside a tile coding parameter structure. + * + * @param p_tcp the tile coding parameter which contain data to destroy. + */ +static void j2k_tcp_data_destroy (opj_tcp_v2_t *p_tcp); /** * Destroys a coding parameter structure. @@ -134,6 +206,35 @@ static void j2k_tcp_destroy (opj_tcp_v2_t *p_tcp); static void j2k_cp_destroy (opj_cp_v2_t *p_cp); +/** + * Writes a SPCod or SPCoc element, i.e. the coding style of a given component of a tile. + * + * @param p_comp_no the component number to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. + * +*/ +static opj_bool j2k_write_SPCod_SPCoc( opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_header_size, + struct opj_event_mgr * p_manager ); + +/** + * Gets the size taken by writing a SPCod or SPCoc for the given tile and component. + * + * @param p_tile_no the tile index. + * @param p_comp_no the component being outputted. + * @param p_j2k the J2K codec. + * + * @return the number of bytes taken by the SPCod element. + */ +static OPJ_UINT32 j2k_get_SPCod_SPCoc_size (opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no ); + /** * Reads a SPCod or SPCoc element, i.e. the coding style of a given component of a tile. * @param p_header_data the data contained in the COM box. @@ -141,13 +242,47 @@ static void j2k_cp_destroy (opj_cp_v2_t *p_cp); * @param p_header_size the size of the data contained in the COM marker. * @param p_manager the user event manager. */ -static opj_bool j2k_read_SPCod_SPCoc( - opj_j2k_v2_t *p_j2k, - OPJ_UINT32 compno, - OPJ_BYTE * p_header_data, - OPJ_UINT32 * p_header_size, - struct opj_event_mgr * p_manager - ); +static opj_bool j2k_read_SPCod_SPCoc( opj_j2k_v2_t *p_j2k, + OPJ_UINT32 compno, + OPJ_BYTE * p_header_data, + OPJ_UINT32 * p_header_size, + opj_event_mgr_t * p_manager ); + +/** + * Gets the size taken by writing SQcd or SQcc element, i.e. the quantization values of a band in the QCD or QCC. + * + * @param p_tile_no the tile index. + * @param p_comp_no the component being outputted. + * @param p_j2k the J2K codec. + * + * @return the number of bytes taken by the SPCod element. + */ +static OPJ_UINT32 j2k_get_SQcd_SQcc_size ( opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no ); + +/** + * Writes a SQcd or SQcc element, i.e. the quantization values of a band in the QCD or QCC. + * + * @param p_tile_no the tile to output. + * @param p_comp_no the component number to output. + * @param p_data the data buffer. + * @param p_header_size pointer to the size of the data buffer, it is changed by the function. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. + * +*/ +static opj_bool j2k_write_SQcd_SQcc(opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_header_size, + opj_event_mgr_t * p_manager); + +/** + * Updates the Tile Length Marker. + */ +static void j2k_update_tlm ( opj_j2k_v2_t * p_j2k, OPJ_UINT32 p_tile_part_size); /** * Reads a SQcd or SQcc element, i.e. the quantization values of a band in the QCD or QCC. @@ -160,41 +295,79 @@ static opj_bool j2k_read_SPCod_SPCoc( * @param p_manager the user event manager. * */ -static opj_bool j2k_read_SQcd_SQcc( - opj_j2k_v2_t *p_j2k, - OPJ_UINT32 compno, - OPJ_BYTE * p_header_data, - OPJ_UINT32 * p_header_size, - struct opj_event_mgr * p_manager - ); +static opj_bool j2k_read_SQcd_SQcc( opj_j2k_v2_t *p_j2k, + OPJ_UINT32 compno, + OPJ_BYTE * p_header_data, + OPJ_UINT32 * p_header_size, + opj_event_mgr_t * p_manager ); /** * Copies the tile component parameters of all the component from the first tile component. * * @param p_j2k the J2k codec. */ -static void j2k_copy_tile_component_parameters( - opj_j2k_v2_t *p_j2k - ); +static void j2k_copy_tile_component_parameters( opj_j2k_v2_t *p_j2k ); /** * Copies the tile quantization parameters of all the component from the first tile component. * * @param p_j2k the J2k codec. */ -static void j2k_copy_tile_quantization_parameters( - opj_j2k_v2_t *p_j2k - ); +static void j2k_copy_tile_quantization_parameters( opj_j2k_v2_t *p_j2k ); /** * Reads the tiles. */ -opj_bool j2k_decode_tiles ( opj_j2k_v2_t *p_j2k, - opj_stream_private_t *p_stream, - opj_event_mgr_t * p_manager); +static opj_bool j2k_decode_tiles ( opj_j2k_v2_t *p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager); + + +static opj_bool j2k_pre_write_tile ( opj_j2k_v2_t * p_j2k, + OPJ_UINT32 p_tile_index, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ); static opj_bool j2k_update_image_data (opj_tcd_v2_t * p_tcd, OPJ_BYTE * p_data, opj_image_t* p_output_image); +static void j2k_get_tile_data (opj_tcd_v2_t * p_tcd, OPJ_BYTE * p_data); + +static opj_bool j2k_post_write_tile (opj_j2k_v2_t * p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 p_data_size, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ); + +/** + * Sets up the procedures to do on writing header. + * Developers wanting to extend the library can add their own writing procedures. + */ +static void j2k_setup_header_writting (opj_j2k_v2_t *p_j2k); + +static opj_bool j2k_write_first_tile_part( opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 p_total_data_size, + opj_stream_private_t *p_stream, + struct opj_event_mgr * p_manager ); + +static opj_bool j2k_write_all_tile_parts( opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 p_total_data_size, + opj_stream_private_t *p_stream, + struct opj_event_mgr * p_manager ); + +/** + * Gets the offset of the header. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_get_end_header( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); /* * ----------------------------------------------------------------------- @@ -207,6 +380,18 @@ Write the SOC marker (Start Of Codestream) @param j2k J2K handle */ static void j2k_write_soc(opj_j2k_t *j2k); + +/** + * Writes the SOC marker (Start Of Codestream) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_soc_v2( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + /** Read the SOC marker (Start of Codestream) @param j2k J2K handle @@ -231,6 +416,18 @@ Write the SIZ marker (image and tile size) @param j2k J2K handle */ static void j2k_write_siz(opj_j2k_t *j2k); + +/** + * Writes the SIZ marker (image and tile size) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_siz_v2( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + /** Read the SIZ marker (image and tile size) @param j2k J2K handle @@ -256,6 +453,18 @@ Write the COM marker (comment) @param j2k J2K handle */ static void j2k_write_com(opj_j2k_t *j2k); + +/** + * Writes the COM marker (comment) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_com_v2( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + /** Read the COM marker (comment) @param j2k J2K handle @@ -291,6 +500,18 @@ Write the COD marker (coding style default) @param j2k J2K handle */ static void j2k_write_cod(opj_j2k_t *j2k); + +/** + * Writes the COD marker (Coding style default) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_cod_v2( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + /** Read the COD marker (coding style default) @param j2k J2K handle @@ -317,6 +538,41 @@ Write the COC marker (coding style component) @param compno Number of the component concerned by the information written */ static void j2k_write_coc(opj_j2k_t *j2k, int compno); + +/** + * Writes the COC marker (Coding style component) + * + * @param p_comp_number the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_coc_v2( opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_comp_number, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); +/** + * Writes the COC marker (Coding style component) + * + * @param p_comp_no the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static void j2k_write_coc_in_memory(opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_comp_no, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + struct opj_event_mgr * p_manager ); + +/** + * Gets the maximum size taken by a coc. + * + * @param p_j2k the jpeg2000 codec to use. + */ +static OPJ_UINT32 j2k_get_max_coc_size(opj_j2k_v2_t *p_j2k); + /** Read the COC marker (coding style component) @param j2k J2K handle @@ -355,6 +611,19 @@ Write the QCD marker (quantization default) @param j2k J2K handle */ static void j2k_write_qcd(opj_j2k_t *j2k); + +/** + * Writes the QCD marker (quantization default) + * + * @param p_comp_number the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_qcd_v2( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + /** Read the QCD marker (quantization default) @param j2k J2K handle @@ -381,6 +650,39 @@ Write the QCC marker (quantization component) @param compno Number of the component concerned by the information written */ static void j2k_write_qcc(opj_j2k_t *j2k, int compno); + +/** + * Writes the QCC marker (quantization component) + * + * @param p_comp_no the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_qcc_v2( opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_comp_no, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + +/** + * Writes the QCC marker (quantization component) + * + * @param p_comp_no the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static void j2k_write_qcc_in_memory(opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_comp_no, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + struct opj_event_mgr * p_manager ); + +/** + * Gets the maximum size taken by a qcc. + */ +static OPJ_UINT32 j2k_get_max_qcc_size (opj_j2k_v2_t *p_j2k); + /** Read the QCC marker (quantization component) @param j2k J2K handle @@ -404,6 +706,47 @@ Write the POC marker (progression order change) @param j2k J2K handle */ static void j2k_write_poc(opj_j2k_t *j2k); + +/** + * Writes the POC marker (Progression Order Change) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_poc_v2( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + +/** + * Writes the POC marker (Progression Order Change) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. + */ +static void j2k_write_poc_in_memory(opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + struct opj_event_mgr * p_manager ); + +/** + * Gets the maximum size taken by the writting of a POC. + */ +static OPJ_UINT32 j2k_get_max_poc_size(opj_j2k_v2_t *p_j2k); + +/** + * Gets the maximum size taken by the toc headers of all the tile parts of any given tile. + */ +static OPJ_UINT32 j2k_get_max_toc_size (opj_j2k_v2_t *p_j2k); + +/** + * Gets the maximum size taken by the headers of the SOT. + * + * @param p_j2k the jpeg2000 codec to use. + */ +static OPJ_UINT32 j2k_get_specific_header_sizes(opj_j2k_v2_t *p_j2k); + /** Read the POC marker (progression order change) @param j2k J2K handle @@ -423,6 +766,7 @@ static opj_bool j2k_read_poc_v2 ( OPJ_UINT32 p_header_size, struct opj_event_mgr * p_manager ); + /** Read the CRG marker (component registration) @param j2k J2K handle @@ -461,6 +805,18 @@ static opj_bool j2k_read_tlm_v2 ( OPJ_UINT32 p_header_size, struct opj_event_mgr * p_manager ); + +/** + * Writes the updated tlm. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_updated_tlm( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + /** Read the PLM marker (packet length, main header) @param j2k J2K handle @@ -513,12 +869,14 @@ static void j2k_read_ppm(opj_j2k_t *j2k); * @param p_header_size the size of the data contained in the POC marker. * @param p_manager the user event manager. */ +#if 0 static opj_bool j2k_read_ppm_v2 ( opj_j2k_v2_t *p_j2k, OPJ_BYTE * p_header_data, OPJ_UINT32 p_header_size, struct opj_event_mgr * p_manager ); +#endif static opj_bool j2k_read_ppm_v3 ( opj_j2k_v2_t *p_j2k, @@ -551,6 +909,18 @@ Write the TLM marker (Mainheader) @param j2k J2K handle */ static void j2k_write_tlm(opj_j2k_t *j2k); + +/** + * Writes the TLM marker (Tile Length Marker) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_tlm_v2( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + /** Write the SOT marker (start of tile-part) @param j2k J2K handle @@ -562,6 +932,19 @@ Read the SOT marker (start of tile-part) */ static void j2k_read_sot(opj_j2k_t *j2k); +/** + * Writes the SOT marker (Start of tile-part) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_sot_v2( opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + const struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + /** * Reads a PPT marker (Packed packet headers, tile-part header) * @@ -582,6 +965,22 @@ Write the SOD marker (start of data) @param tile_coder Pointer to a TCD handle */ static void j2k_write_sod(opj_j2k_t *j2k, void *tile_coder); + +/** + * Writes the SOD marker (Start of data) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_sod_v2( opj_j2k_v2_t *p_j2k, + struct opj_tcd_v2 * p_tile_coder, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 p_total_data_size, + const struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + /** Read the SOD marker (start of data) @param j2k J2K handle @@ -602,6 +1001,18 @@ static opj_bool j2k_read_sod_v2 ( struct opj_event_mgr * p_manager ); +/** + * Updates the Tile Length Marker. + */ +void j2k_update_tlm (opj_j2k_v2_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; + + opj_write_bytes(p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current,p_tile_part_size,4); /* PSOT */ + p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current += 4; +} + /** Write the RGN marker (region-of-interest) @param j2k J2K handle @@ -609,6 +1020,22 @@ Write the RGN marker (region-of-interest) @param tileno Number of the tile concerned by the information written */ static void j2k_write_rgn(opj_j2k_t *j2k, int compno, int tileno); + +/** + * Writes the RGN marker (Region Of Interest) + * + * @param p_tile_no the tile to output + * @param p_comp_no the component to output + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_rgn_v2( opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + /** Read the RGN marker (region-of-interest) @param j2k J2K handle @@ -630,6 +1057,17 @@ static opj_bool j2k_read_rgn_v2 ( struct opj_event_mgr * p_manager ) ; +/** + * Writes the EOC marker (End of Codestream) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_eoc_v2( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + /** Write the EOC marker (end of codestream) @param j2k J2K handle @@ -649,11 +1087,37 @@ static void j2k_read_eoc(opj_j2k_t *j2k); * @param p_header_size the size of the data contained in the SOD marker. * @param p_manager the user event manager. */ +#if 0 static opj_bool j2k_read_eoc_v2 ( opj_j2k_v2_t *p_j2k, struct opj_stream_private *p_stream, struct opj_event_mgr * p_manager ) ; +#endif + + + +/** + * Writes the CBD-MCT-MCC-MCO markers (Multi components transform) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_mct_data_group( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + +/** + * Inits the Info + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_init_info( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); /** Read an unknown marker @@ -696,6 +1160,18 @@ static opj_bool j2k_read_unk_v2 ( opj_j2k_v2_t *p_j2k, OPJ_UINT32 *output_marker, struct opj_event_mgr * p_manager ); +/** + * Writes the MCT marker (Multiple Component Transform) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_mct_record( opj_j2k_v2_t *p_j2k, + opj_mct_data_t * p_mct_record, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + /** * Reads a MCT marker (Multiple Component Transform) * @@ -709,6 +1185,19 @@ static opj_bool j2k_read_mct ( opj_j2k_v2_t *p_j2k, OPJ_UINT32 p_header_size, struct opj_event_mgr * p_manager ); +/** + * Writes the MCC marker (Multiple Component Collection) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_mcc_record( opj_j2k_v2_t *p_j2k, + struct opj_simple_mcc_decorrelation_data * p_mcc_record, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + + /** * Reads a MCC marker (Multiple Component Collection) * @@ -718,9 +1207,20 @@ static opj_bool j2k_read_mct ( opj_j2k_v2_t *p_j2k, * @param p_manager the user event manager. */ static opj_bool j2k_read_mcc ( opj_j2k_v2_t *p_j2k, - OPJ_BYTE * p_header_data, - OPJ_UINT32 p_header_size, - struct opj_event_mgr * p_manager ); + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager ); + +/** + * Writes the MCO marker (Multiple component transformation ordering) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_mco( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); /** * Reads a MCO marker (Multiple Component Transform Ordering) @@ -752,6 +1252,29 @@ static void j2k_write_float_to_int32 (const void * p_src_data, void * p_dest_da static void j2k_write_float_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem); static void j2k_write_float_to_float64 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem); + +/** + * Ends the encoding, i.e. frees memory. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_end_encoding( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + +/** + * Writes the CBD marker (Component bit depth definition) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_cbd( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + /** * Reads a CBD marker (Component bit depth definition) * @param p_header_data the data contained in the CBD box. @@ -764,6 +1287,89 @@ static opj_bool j2k_read_cbd ( opj_j2k_v2_t *p_j2k, OPJ_UINT32 p_header_size, struct opj_event_mgr * p_manager); +/** + * Writes the image components. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_image_components( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + +/** + * Writes regions of interests. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_regions( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + +/** + * Writes EPC ???? + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_epc( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + +/** + * Checks the progression order changes values. Tells of the poc given as input are valid. + * A nice message is outputted at errors. + * + * @param p_pocs the progression order changes. + * @param p_nb_pocs the number of progression order changes. + * @param p_nb_resolutions the number of resolutions. + * @param numcomps the number of components + * @param numlayers the number of layers. + * + * @return true if the pocs are valid. + */ +static opj_bool j2k_check_poc_val( const opj_poc_t *p_pocs, + OPJ_UINT32 p_nb_pocs, + OPJ_UINT32 p_nb_resolutions, + OPJ_UINT32 numcomps, + OPJ_UINT32 numlayers, + opj_event_mgr_t * p_manager); + +/** + * Gets the number of tile parts used for the given change of progression (if any) and the given tile. + * + * @param cp the coding parameters. + * @param pino the offset of the given poc (i.e. its position in the coding parameter). + * @param tileno the given tile. + * + * @return the number of tile parts. + */ +static OPJ_UINT32 j2k_get_num_tp_v2( opj_cp_v2_t *cp, OPJ_UINT32 pino, OPJ_UINT32 tileno); + +/** mem allocation for TLM marker*/ +static int j2k_calculate_tp(opj_cp_t *cp,int img_numcomp,opj_image_t *image,opj_j2k_t *j2k ); + +/** + * Calculates the total number of tile parts needed by the encoder to + * encode such an image. If not enough memory is available, then the function return false. + * + * @param p_nb_tiles pointer that will hold the number of tile parts. + * @param cp the coding parameters for the image. + * @param image the image to encode. + * @param p_j2k the p_j2k encoder. + * @param p_manager the user event manager. + * + * @return true if the function was successful, false else. + */ +static opj_bool j2k_calculate_tp_v2(opj_j2k_v2_t *p_j2k, + opj_cp_v2_t *cp, + OPJ_UINT32 * p_nb_tiles, + opj_image_t *image, + opj_event_mgr_t * p_manager); static void j2k_dump_MH_info(opj_j2k_v2_t* p_j2k, FILE* out_stream); @@ -901,7 +1507,7 @@ const opj_dec_memory_marker_handler_t j2k_memory_marker_handler_tab [] = {J2K_MS_SEC, J2K_DEC_STATE_MH, j2k_read_sec}, {J2K_MS_INSEC, 0, j2k_read_insec} #endif /* USE_JPSEC */ - {J2K_MS_UNK, J2K_STATE_MH | J2K_STATE_TPH, 0}//j2k_read_unk_v2} + {J2K_MS_UNK, J2K_STATE_MH | J2K_STATE_TPH, 0}/*j2k_read_unk_v2}*/ }; @@ -1116,6 +1722,120 @@ char *j2k_convert_progression_order(OPJ_PROG_ORDER prg_order){ return po->str_prog; } +/** + * Checks the progression order changes values. Tells if the poc given as input are valid. + * + * @param p_pocs the progression order changes. + * @param p_nb_pocs the number of progression order changes. + * @param p_nb_resolutions the number of resolutions. + * @param numcomps the number of components + * @param numlayers the number of layers. + * @param p_manager the user event manager. + * + * @return true if the pocs are valid. + */ +opj_bool j2k_check_poc_val( const opj_poc_t *p_pocs, + OPJ_UINT32 p_nb_pocs, + OPJ_UINT32 p_nb_resolutions, + OPJ_UINT32 p_num_comps, + OPJ_UINT32 p_num_layers, + opj_event_mgr_t * p_manager) +{ + OPJ_UINT32* packet_array; + OPJ_UINT32 index , resno, compno, layno; + OPJ_UINT32 i; + OPJ_UINT32 step_c = 1; + 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, sizeof(OPJ_UINT32)); + if (packet_array == 00) { + opj_event_msg_v2(p_manager , EVT_ERROR, "Not enough memory for checking the poc values.\n"); + return OPJ_FALSE; + } + memset(packet_array,0,step_l * p_num_layers* sizeof(OPJ_UINT32)); + + if (p_nb_pocs == 0) { + 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 ; + + 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 = 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; + } + + index = 0; + for (layno = 0; layno < p_num_layers ; ++layno) { + 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; + index += step_c; + } + } + } + + if (loss) { + opj_event_msg_v2(p_manager , EVT_ERROR, "Missing packets possible loss of data\n"); + } + + opj_free(packet_array); + + return !loss; +} + /* ----------------------------------------------------------------------- */ static int j2k_get_num_tp(opj_cp_t *cp,int pino,int tileno){ char *prog; @@ -1152,6 +1872,73 @@ static int j2k_get_num_tp(opj_cp_t *cp,int pino,int tileno){ return tpnum; } +/** + * Gets the number of tile parts used for the given change of progression (if any) and the given tile. + * + * @param cp the coding parameters. + * @param pino the offset of the given poc (i.e. its position in the coding parameter). + * @param tileno the given tile. + * + * @return the number of tile parts. + */ +OPJ_UINT32 j2k_get_num_tp_v2(opj_cp_v2_t *cp, OPJ_UINT32 pino, OPJ_UINT32 tileno) +{ + const OPJ_CHAR *prog = 00; + OPJ_UINT32 i; + OPJ_UINT32 tpnum = 1; + opj_tcp_v2_t *tcp = 00; + opj_poc_t * l_current_poc = 00; + + /* preconditions */ + assert(tileno < (cp->tw * cp->th)); + assert(pino < (cp->tcps[tileno].numpocs + 1)); + + /* get the given tile coding parameter */ + tcp = &cp->tcps[tileno]; + assert(tcp != 00); + + l_current_poc = &(tcp->pocs[pino]); + assert(l_current_poc != 0); + + /* get the progression order as a character string */ + prog = j2k_convert_progression_order(tcp->prg); + assert(strlen(prog) > 0); + + if (cp->m_specific_param.m_enc.m_tp_on == 1) { + for (i=0;i<4;++i) { + switch (prog[i]) + { + /* component wise */ + case 'C': + tpnum *= l_current_poc->compE; + break; + /* resolution wise */ + case 'R': + tpnum *= l_current_poc->resE; + break; + /* precinct wise */ + case 'P': + tpnum *= l_current_poc->prcE; + break; + /* layer wise */ + case 'L': + tpnum *= l_current_poc->layE; + break; + } + /* whould 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; + } + } + } + else { + tpnum=1; + } + + return tpnum; +} + /** mem allocation for TLM marker*/ int j2k_calculate_tp(opj_cp_t *cp,int img_numcomp,opj_image_t *image,opj_j2k_t *j2k ){ int pino,tileno,totnum_tp=0; @@ -1182,6 +1969,95 @@ int j2k_calculate_tp(opj_cp_t *cp,int img_numcomp,opj_image_t *image,opj_j2k_t * return totnum_tp; } +/** + * Calculates the total number of tile parts needed by the encoder to + * encode such an image. If not enough memory is available, then the function return false. + * + * @param p_nb_tiles pointer that will hold the number of tile parts. + * @param cp the coding parameters for the image. + * @param image the image to encode. + * @param p_j2k the p_j2k encoder. + * @param p_manager the user event manager. + * + * @return true if the function was successful, false else. + */ +opj_bool j2k_calculate_tp_v2( opj_j2k_v2_t *p_j2k, + opj_cp_v2_t *cp, + OPJ_UINT32 * p_nb_tiles, + opj_image_t *image, + opj_event_mgr_t * p_manager) +{ + OPJ_UINT32 pino,tileno; + OPJ_UINT32 l_nb_tiles; + opj_tcp_v2_t *tcp; + + /* preconditions */ + assert(p_nb_tiles != 00); + assert(cp != 00); + assert(image != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + l_nb_tiles = cp->tw * cp->th; + * p_nb_tiles = 0; + tcp = cp->tcps; + + /* INDEX >> */ + /* TODO mergeV2: check this part which use cstr_info */ + /*if (p_j2k->cstr_info) { + opj_tile_info_t * l_info_tile_ptr = p_j2k->cstr_info->tile; + + for (tileno = 0; tileno < l_nb_tiles; ++tileno) { + OPJ_UINT32 cur_totnum_tp = 0; + + pi_update_encoding_parameters(image,cp,tileno); + + for (pino = 0; pino <= tcp->numpocs; ++pino) + { + OPJ_UINT32 tp_num = j2k_get_num_tp_v2(cp,pino,tileno); + + *p_nb_tiles = *p_nb_tiles + tp_num; + + cur_totnum_tp += tp_num; + } + + tcp->m_nb_tile_parts = cur_totnum_tp; + + l_info_tile_ptr->tp = (opj_tp_info_t *) opj_malloc(cur_totnum_tp * sizeof(opj_tp_info_t)); + if (l_info_tile_ptr->tp == 00) { + return OPJ_FALSE; + } + + memset(l_info_tile_ptr->tp,0,cur_totnum_tp * sizeof(opj_tp_info_t)); + + l_info_tile_ptr->num_tps = cur_totnum_tp; + + ++l_info_tile_ptr; + ++tcp; + } + } + else */{ + for (tileno = 0; tileno < l_nb_tiles; ++tileno) { + OPJ_UINT32 cur_totnum_tp = 0; + + pi_update_encoding_parameters(image,cp,tileno); + + for (pino = 0; pino <= tcp->numpocs; ++pino) { + OPJ_UINT32 tp_num = j2k_get_num_tp_v2(cp,pino,tileno); + + *p_nb_tiles = *p_nb_tiles + tp_num; + + cur_totnum_tp += tp_num; + } + tcp->m_nb_tile_parts = cur_totnum_tp; + + ++tcp; + } + } + + return OPJ_TRUE; +} + static void j2k_write_soc(opj_j2k_t *j2k) { opj_cio_t *cio = j2k->cio; cio_write(cio, J2K_MS_SOC, 2); @@ -1198,6 +2074,47 @@ static void j2k_write_soc(opj_j2k_t *j2k) { /* <m_specific_param.m_encoder.m_header_tile_data; + + /* write SOC identifier */ + opj_write_bytes(l_start_stream,J2K_MS_SOC,2); + + if (opj_stream_write_data(p_stream,l_start_stream,2,p_manager) != 2) { + return OPJ_FALSE; + } + +/* UniPG>> */ +#ifdef USE_JPWL + /* update markers struct */ +/* + j2k_add_marker(p_j2k->cstr_info, J2K_MS_SOC, p_stream_tell(p_stream) - 2, 2); +*/ + assert( 0 && "TODO" ); +#endif /* USE_JPWL */ +/* <state = J2K_STATE_MHSIZ; /* Index */ @@ -1250,7 +2167,7 @@ static opj_bool j2k_read_soc_v2( opj_j2k_v2_t *p_j2k, } static void j2k_write_siz(opj_j2k_t *j2k) { - int i; + OPJ_UINT32 i; int lenp, len; opj_cio_t *cio = j2k->cio; @@ -1284,8 +2201,110 @@ static void j2k_write_siz(opj_j2k_t *j2k) { j2k_add_mhmarker(j2k->cstr_info, J2K_MS_SIZ, lenp, len); } +/** + * Writes the SIZ marker (image and tile size) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +opj_bool j2k_write_siz_v2( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) +{ + OPJ_UINT32 i; + OPJ_UINT32 l_size_len; + OPJ_BYTE * l_current_ptr; + opj_image_t * l_image = 00; + opj_cp_v2_t *cp = 00; + opj_image_comp_t * l_img_comp = 00; + + /* preconditions */ + assert(p_stream != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + l_image = p_j2k->m_private_image; + cp = &(p_j2k->m_cp); + l_size_len = 40 + 3 * l_image->numcomps; + l_img_comp = l_image->comps; + + if (l_size_len > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) { + + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = (OPJ_BYTE*)opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_size_len); + if (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) { + return OPJ_FALSE; + } + + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_size_len; + } + + l_current_ptr = p_j2k->m_specific_param.m_encoder.m_header_tile_data; + + /* write SOC identifier */ + opj_write_bytes(l_current_ptr,J2K_MS_SIZ,2); /* SIZ */ + l_current_ptr+=2; + + opj_write_bytes(l_current_ptr,l_size_len-2,2); /* L_SIZ */ + l_current_ptr+=2; + + opj_write_bytes(l_current_ptr, cp->rsiz, 2); /* Rsiz (capabilities) */ + l_current_ptr+=2; + + opj_write_bytes(l_current_ptr, l_image->x1, 4); /* Xsiz */ + l_current_ptr+=4; + + opj_write_bytes(l_current_ptr, l_image->y1, 4); /* Ysiz */ + l_current_ptr+=4; + + opj_write_bytes(l_current_ptr, l_image->x0, 4); /* X0siz */ + l_current_ptr+=4; + + opj_write_bytes(l_current_ptr, l_image->y0, 4); /* Y0siz */ + l_current_ptr+=4; + + opj_write_bytes(l_current_ptr, cp->tdx, 4); /* XTsiz */ + l_current_ptr+=4; + + opj_write_bytes(l_current_ptr, cp->tdy, 4); /* YTsiz */ + l_current_ptr+=4; + + opj_write_bytes(l_current_ptr, cp->tx0, 4); /* XT0siz */ + l_current_ptr+=4; + + opj_write_bytes(l_current_ptr, cp->ty0, 4); /* YT0siz */ + l_current_ptr+=4; + + opj_write_bytes(l_current_ptr, l_image->numcomps, 2); /* Csiz */ + l_current_ptr+=2; + + for (i = 0; i < l_image->numcomps; ++i) { + /* TODO here with MCT ? */ + opj_write_bytes(l_current_ptr, l_img_comp->prec - 1 + (l_img_comp->sgnd << 7), 1); /* Ssiz_i */ + ++l_current_ptr; + + opj_write_bytes(l_current_ptr, l_img_comp->dx, 1); /* XRsiz_i */ + ++l_current_ptr; + + opj_write_bytes(l_current_ptr, l_img_comp->dy, 1); /* YRsiz_i */ + ++l_current_ptr; + + ++l_img_comp; + } + + if (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_size_len,p_manager) != l_size_len) { + return OPJ_FALSE; + } + + return OPJ_TRUE; +} + static void j2k_read_siz(opj_j2k_t *j2k) { - int len, i; + int len; + OPJ_UINT32 i; opj_cio_t *cio = j2k->cio; opj_image_t *image = j2k->image; @@ -1302,12 +2321,16 @@ static void j2k_read_siz(opj_j2k_t *j2k) { cp->tx0 = cio_read(cio, 4); /* XT0siz */ cp->ty0 = cio_read(cio, 4); /* YT0siz */ + /* the following code triggers: */ + /* warning: comparison of unsigned expression < 0 is always false */ +#if 0 if ((image->x0<0)||(image->x1<0)||(image->y0<0)||(image->y1<0)) { opj_event_msg(j2k->cinfo, EVT_ERROR, "%s: invalid image size (x0:%d, x1:%d, y0:%d, y1:%d)\n", image->x0,image->x1,image->y0,image->y1); return; } +#endif image->numcomps = cio_read(cio, 2); /* Csiz */ @@ -1324,7 +2347,8 @@ static void j2k_read_siz(opj_j2k_t *j2k) { return; } } - if (image->numcomps != ((len - 38) / 3)) { + assert( len >= 38 ); + if (image->numcomps != (OPJ_UINT32)((len - 38) / 3)) { opj_event_msg(j2k->cinfo, JPWL_ASSUME ? EVT_WARNING : EVT_ERROR, "JPWL: Csiz is %d => space in SIZ only for %d comps.!!!\n", image->numcomps, ((len - 38) / 3)); @@ -1334,7 +2358,7 @@ static void j2k_read_siz(opj_j2k_t *j2k) { } /* we try to correct */ opj_event_msg(j2k->cinfo, EVT_WARNING, "- trying to adjust this\n"); - if (image->numcomps < ((len - 38) / 3)) { + if (image->numcomps < (OPJ_UINT32)((len - 38) / 3)) { len = 38 + 3 * image->numcomps; opj_event_msg(j2k->cinfo, EVT_WARNING, "- setting Lsiz to %d => HYPOTHESIS!!!\n", len); @@ -1456,7 +2480,7 @@ static void j2k_read_siz(opj_j2k_t *j2k) { } #endif /* USE_JPWL */ - for (i = 0; i < cp->tw * cp->th; i++) { + for (i = 0; i < (OPJ_UINT32)cp->tw * cp->th; i++) { cp->tcps[i].POC = 0; cp->tcps[i].numpocs = 0; cp->tcps[i].first = 1; @@ -1470,7 +2494,7 @@ static void j2k_read_siz(opj_j2k_t *j2k) { cp->ppm_store = 0; j2k->default_tcp->tccps = (opj_tccp_t*) opj_calloc(image->numcomps, sizeof(opj_tccp_t)); - for (i = 0; i < cp->tw * cp->th; i++) { + for (i = 0; i < (OPJ_UINT32)cp->tw * cp->th; i++) { cp->tcps[i].tccps = (opj_tccp_t*) opj_malloc(image->numcomps * sizeof(opj_tccp_t)); } j2k->tile_data = (unsigned char**) opj_calloc(cp->tw * cp->th, sizeof(unsigned char*)); @@ -1519,7 +2543,7 @@ opj_bool j2k_read_siz_v2 ( opj_image_comp_t * l_img_comp = 00; opj_tcp_v2_t * l_current_tile_param = 00; - // preconditions + /* preconditions */ assert(p_j2k != 00); assert(p_manager != 00); assert(p_header_data != 00); @@ -1527,7 +2551,7 @@ opj_bool j2k_read_siz_v2 ( l_image = p_j2k->m_private_image; l_cp = &(p_j2k->m_cp); - // minimum size == 39 - 3 (= minimum component parameter) + /* minimum size == 39 - 3 (= minimum component parameter) */ if (p_header_size < 36) { opj_event_msg_v2(p_manager, EVT_ERROR, "Error with SIZ marker size\n"); return OPJ_FALSE; @@ -1618,7 +2642,7 @@ opj_bool j2k_read_siz_v2 ( } #endif /* USE_JPWL */ - // Allocate the resulting image components + /* Allocate the resulting image components */ l_image->comps = (opj_image_comp_t*) opj_calloc(l_image->numcomps, sizeof(opj_image_comp_t)); if (l_image->comps == 00){ l_image->numcomps = 0; @@ -1629,7 +2653,7 @@ opj_bool j2k_read_siz_v2 ( memset(l_image->comps,0,l_image->numcomps * sizeof(opj_image_comp_t)); l_img_comp = l_image->comps; - // Read the component information + /* Read the component information */ for (i = 0; i < l_image->numcomps; ++i){ OPJ_UINT32 tmp; opj_read_bytes(p_header_data,&tmp,1); /* Ssiz_i */ @@ -1638,10 +2662,10 @@ opj_bool j2k_read_siz_v2 ( l_img_comp->sgnd = tmp >> 7; opj_read_bytes(p_header_data,&tmp,1); /* XRsiz_i */ ++p_header_data; - l_img_comp->dx = (OPJ_INT32)tmp; // should be between 1 and 255 + l_img_comp->dx = (OPJ_INT32)tmp; /* should be between 1 and 255 */ opj_read_bytes(p_header_data,&tmp,1); /* YRsiz_i */ ++p_header_data; - l_img_comp->dy = (OPJ_INT32)tmp; // should be between 1 and 255 + l_img_comp->dy = (OPJ_INT32)tmp; /* should be between 1 and 255 */ #ifdef USE_JPWL if (l_cp->correct) { @@ -1675,12 +2699,12 @@ opj_bool j2k_read_siz_v2 ( ++l_img_comp; } - // Compute the number of tiles + /* Compute the number of tiles */ l_cp->tw = int_ceildiv(l_image->x1 - l_cp->tx0, l_cp->tdx); l_cp->th = int_ceildiv(l_image->y1 - l_cp->ty0, l_cp->tdy); l_nb_tiles = l_cp->tw * l_cp->th; - // Define the tiles which will be decoded + /* Define the tiles which will be decoded */ if (p_j2k->m_specific_param.m_decoder.m_discard_tiles) { p_j2k->m_specific_param.m_decoder.m_start_tile_x = (p_j2k->m_specific_param.m_decoder.m_start_tile_x - l_cp->tx0) / l_cp->tdx; p_j2k->m_specific_param.m_decoder.m_start_tile_y = (p_j2k->m_specific_param.m_decoder.m_start_tile_y - l_cp->ty0) / l_cp->tdy; @@ -1803,7 +2827,7 @@ opj_bool j2k_read_siz_v2 ( ++l_current_tile_param; } - p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_MH; // FIXME J2K_DEC_STATE_MH; + p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_MH; /* FIXME J2K_DEC_STATE_MH; */ opj_image_comp_header_update(l_image,l_cp); return OPJ_TRUE; @@ -1838,6 +2862,63 @@ static void j2k_write_com(opj_j2k_t *j2k) { } } +/** + * Writes the COM marker (comment) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +opj_bool j2k_write_com_v2( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) +{ + OPJ_UINT32 l_comment_size; + OPJ_UINT32 l_total_com_size; + const OPJ_CHAR *l_comment; + OPJ_BYTE * l_current_ptr = 00; + + // preconditions + assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); + + l_comment = p_j2k->m_cp.comment; + l_comment_size = strlen(l_comment); + l_total_com_size = l_comment_size + 6; + + if (l_total_com_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = (OPJ_BYTE*)opj_realloc( p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_total_com_size); + + if(! p_j2k->m_specific_param.m_encoder.m_header_tile_data) { + return OPJ_FALSE; + } + + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_total_com_size; + } + + l_current_ptr = p_j2k->m_specific_param.m_encoder.m_header_tile_data; + + opj_write_bytes(l_current_ptr,J2K_MS_COM , 2); /* COM */ + l_current_ptr+=2; + + opj_write_bytes(l_current_ptr,l_total_com_size - 2 , 2); /* L_COM */ + l_current_ptr+=2; + + opj_write_bytes(l_current_ptr,1 , 2); /* General use (IS 8859-15:1999 (Latin) values) */ + l_current_ptr+=2; + + memcpy( l_current_ptr,l_comment,l_comment_size); + + if (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_total_com_size,p_manager) != l_total_com_size) { + return OPJ_FALSE; + } + + return OPJ_TRUE; +} + static void j2k_read_com(opj_j2k_t *j2k) { int len; @@ -1860,16 +2941,17 @@ opj_bool j2k_read_com_v2 ( struct opj_event_mgr * p_manager ) { - // preconditions + /* preconditions */ assert(p_j2k != 00); assert(p_manager != 00); assert(p_header_data != 00); + (void)p_header_size; return OPJ_TRUE; } static void j2k_write_cox(opj_j2k_t *j2k, int compno) { - int i; + OPJ_UINT32 i; opj_cp_t *cp = j2k->cp; opj_tcp_t *tcp = &cp->tcps[j2k->curtileno]; @@ -1890,7 +2972,7 @@ static void j2k_write_cox(opj_j2k_t *j2k, int compno) { } static void j2k_read_cox(opj_j2k_t *j2k, int compno) { - int i; + OPJ_UINT32 i; opj_cp_t *cp = j2k->cp; opj_tcp_t *tcp = j2k->state == J2K_STATE_TPH ? &cp->tcps[j2k->curtileno] : j2k->default_tcp; @@ -1899,8 +2981,9 @@ static void j2k_read_cox(opj_j2k_t *j2k, int compno) { tccp->numresolutions = cio_read(cio, 1) + 1; /* SPcox (D) */ - // If user wants to remove more resolutions than the codestream contains, return error - if (cp->reduce >= tccp->numresolutions) { + /* If user wants to remove more resolutions than the codestream contains, return error*/ + assert(cp->reduce >= 0); + if ((OPJ_UINT32)cp->reduce >= tccp->numresolutions) { opj_event_msg(j2k->cinfo, 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); j2k->state |= J2K_STATE_ERR; @@ -1965,8 +3048,87 @@ static void j2k_write_cod(opj_j2k_t *j2k) { } +/** + * Writes the COD marker (Coding style default) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +opj_bool j2k_write_cod_v2( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) +{ + opj_cp_v2_t *l_cp = 00; + opj_tcp_v2_t *l_tcp = 00; + OPJ_UINT32 l_code_size,l_remaining_size; + OPJ_BYTE * l_current_data = 00; + + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_cp = &(p_j2k->m_cp); + l_tcp = &l_cp->tcps[p_j2k->m_current_tile_number]; + l_code_size = 9 + j2k_get_SPCod_SPCoc_size(p_j2k,p_j2k->m_current_tile_number,0); + l_remaining_size = l_code_size; + + if (l_code_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = (OPJ_BYTE*)opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_code_size); + + if (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) { + return OPJ_FALSE; + } + + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_code_size; + } + + l_current_data = p_j2k->m_specific_param.m_encoder.m_header_tile_data; + + opj_write_bytes(l_current_data,J2K_MS_COD,2); /* COD */ + l_current_data += 2; + + opj_write_bytes(l_current_data,l_code_size-2,2); /* L_COD */ + l_current_data += 2; + + opj_write_bytes(l_current_data,l_tcp->csty,1); /* Scod */ + ++l_current_data; + + opj_write_bytes(l_current_data,l_tcp->prg,1); /* SGcod (A) */ + ++l_current_data; + + opj_write_bytes(l_current_data,l_tcp->numlayers,2); /* SGcod (B) */ + l_current_data+=2; + + opj_write_bytes(l_current_data,l_tcp->mct,1); /* SGcod (C) */ + ++l_current_data; + + l_remaining_size -= 9; + + if (! j2k_write_SPCod_SPCoc(p_j2k,p_j2k->m_current_tile_number,0,l_current_data,&l_remaining_size,p_manager)) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error writting COD marker\n"); + return OPJ_FALSE; + } + + if (l_remaining_size != 0) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error writting COD marker\n"); + return OPJ_FALSE; + } + + if (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_code_size,p_manager) != l_code_size) { + return OPJ_FALSE; + } + + return OPJ_TRUE; +} + static void j2k_read_cod(opj_j2k_t *j2k) { - int len, i, pos; + int len, pos; + OPJ_UINT32 i; opj_cio_t *cio = j2k->cio; opj_cp_t *cp = j2k->cp; @@ -2012,7 +3174,7 @@ opj_bool j2k_read_cod_v2 ( struct opj_event_mgr * p_manager ) { - // loop + /* loop */ OPJ_UINT32 i; OPJ_UINT32 l_tmp; opj_cp_v2_t *l_cp = 00; @@ -2046,7 +3208,7 @@ opj_bool j2k_read_cod_v2 ( opj_read_bytes(p_header_data,&l_tcp->numlayers,2); /* SGcod (B) */ p_header_data+=2; - // If user didn't set a number layer to decode take the max specify in the codestream. + /* If user didn't set a number layer to decode take the max specify in the codestream. */ if (l_cp->m_specific_param.m_dec.m_layer) { l_tcp->num_layers_to_decode = l_cp->m_specific_param.m_dec.m_layer; } @@ -2078,7 +3240,7 @@ opj_bool j2k_read_cod_v2 ( /* Index */ #ifdef WIP_REMOVE_MSD if (p_j2k->cstr_info) { - //opj_codestream_info_t *l_cstr_info = p_j2k->cstr_info; + /*opj_codestream_info_t *l_cstr_info = p_j2k->cstr_info;*/ p_j2k->cstr_info->prog = l_tcp->prg; p_j2k->cstr_info->numlayers = l_tcp->numlayers; p_j2k->cstr_info->numdecompos = (OPJ_INT32*) opj_malloc(l_image->numcomps * sizeof(OPJ_UINT32)); @@ -2111,6 +3273,130 @@ static void j2k_write_coc(opj_j2k_t *j2k, int compno) { cio_seek(cio, lenp + len); } +/** + * Writes the COC marker (Coding style component) + * + * @param p_comp_no the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +opj_bool j2k_write_coc_v2( opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_comp_no, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) +{ + OPJ_UINT32 l_coc_size,l_remaining_size; + OPJ_UINT32 l_comp_room; + + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_comp_room = (p_j2k->m_private_image->numcomps <= 256) ? 1 : 2; + + l_coc_size = 5 + l_comp_room + j2k_get_SPCod_SPCoc_size(p_j2k,p_j2k->m_current_tile_number,p_comp_no); + + if (l_coc_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = (OPJ_BYTE*)opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_coc_size); + if (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) { + return OPJ_FALSE; + } + + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_coc_size; + } + + j2k_write_coc_in_memory(p_j2k,p_comp_no,p_j2k->m_specific_param.m_encoder.m_header_tile_data,&l_remaining_size,p_manager); + + if (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_coc_size,p_manager) != l_coc_size) { + return OPJ_FALSE; + } + + return OPJ_TRUE; +} + +/** + * Writes the COC marker (Coding style component) + * + * @param p_comp_no the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +void j2k_write_coc_in_memory( opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_comp_no, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + struct opj_event_mgr * p_manager ) +{ + opj_cp_v2_t *l_cp = 00; + opj_tcp_v2_t *l_tcp = 00; + OPJ_UINT32 l_coc_size,l_remaining_size; + OPJ_BYTE * l_current_data = 00; + opj_image_t *l_image = 00; + OPJ_UINT32 l_comp_room; + + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + + l_cp = &(p_j2k->m_cp); + l_tcp = &l_cp->tcps[p_j2k->m_current_tile_number]; + l_image = p_j2k->m_private_image; + l_comp_room = (l_image->numcomps <= 256) ? 1 : 2; + + l_coc_size = 5 + l_comp_room + j2k_get_SPCod_SPCoc_size(p_j2k,p_j2k->m_current_tile_number,p_comp_no); + l_remaining_size = l_coc_size; + + l_current_data = p_data; + + opj_write_bytes(l_current_data,J2K_MS_COC,2); /* COC */ + l_current_data += 2; + + opj_write_bytes(l_current_data,l_coc_size-2,2); /* L_COC */ + l_current_data += 2; + + opj_write_bytes(l_current_data,p_comp_no, l_comp_room); /* Ccoc */ + l_current_data+=l_comp_room; + + opj_write_bytes(l_current_data, l_tcp->tccps[p_comp_no].csty, 1); /* Scoc */ + ++l_current_data; + + l_remaining_size -= (5 + l_comp_room); + j2k_write_SPCod_SPCoc(p_j2k,p_j2k->m_current_tile_number,0,l_current_data,&l_remaining_size,p_manager); + * p_data_written = l_coc_size; +} + +/** + * Gets the maximum size taken by a coc. + * + * @param p_j2k the jpeg2000 codec to use. + */ +OPJ_UINT32 j2k_get_max_coc_size(opj_j2k_v2_t *p_j2k) +{ + OPJ_UINT32 i,j; + OPJ_UINT32 l_nb_comp; + OPJ_UINT32 l_nb_tiles; + OPJ_UINT32 l_max = 0; + + /* preconditions */ + + l_nb_tiles = p_j2k->m_cp.tw * p_j2k->m_cp.th ; + l_nb_comp = p_j2k->m_private_image->numcomps; + + for (i=0;inumcomps <= 256 ? 1 : 2; - // make sure room is sufficient + /* make sure room is sufficient*/ if (p_header_size < l_comp_room + 1) { opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading COC marker\n"); return OPJ_FALSE; @@ -2303,45 +3589,114 @@ static void j2k_write_qcd(opj_j2k_t *j2k) { j2k_add_mhmarker(j2k->cstr_info, J2K_MS_QCD, lenp, len); } -static void j2k_read_qcd(opj_j2k_t *j2k) { - int len, i, pos; - - opj_cio_t *cio = j2k->cio; - opj_image_t *image = j2k->image; - - len = cio_read(cio, 2); /* Lqcd */ - pos = cio_tell(cio); - for (i = 0; i < image->numcomps; i++) { - cio_seek(cio, pos); - j2k_read_qcx(j2k, i, len - 2); - } -} - /** - * Reads a QCD marker (Quantization defaults) - * @param p_header_data the data contained in the QCD box. - * @param p_j2k the jpeg2000 codec. - * @param p_header_size the size of the data contained in the QCD marker. + * Writes the QCD marker (quantization default) + * + * @param p_comp_number the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. * @param p_manager the user event manager. */ -opj_bool j2k_read_qcd_v2 ( - opj_j2k_v2_t *p_j2k, - OPJ_BYTE * p_header_data, - OPJ_UINT32 p_header_size, - struct opj_event_mgr * p_manager - ) +opj_bool j2k_write_qcd_v2( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) { + opj_cp_v2_t *l_cp = 00; + opj_tcp_v2_t *l_tcp = 00; + OPJ_UINT32 l_qcd_size,l_remaining_size; + OPJ_BYTE * l_current_data = 00; + /* preconditions */ - assert(p_header_data != 00); assert(p_j2k != 00); assert(p_manager != 00); + assert(p_stream != 00); - if (! j2k_read_SQcd_SQcc(p_j2k,0,p_header_data,&p_header_size,p_manager)) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading QCD marker\n"); - return OPJ_FALSE; - } + l_cp = &(p_j2k->m_cp); + l_tcp = &l_cp->tcps[p_j2k->m_current_tile_number]; + l_qcd_size = 4 + j2k_get_SQcd_SQcc_size(p_j2k,p_j2k->m_current_tile_number,0); + l_remaining_size = l_qcd_size; - if (p_header_size != 0) { + if (l_qcd_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = (OPJ_BYTE*)opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_qcd_size); + + if (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) { + return OPJ_FALSE; + } + + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_qcd_size; + } + + l_current_data = p_j2k->m_specific_param.m_encoder.m_header_tile_data; + + opj_write_bytes(l_current_data,J2K_MS_QCD,2); /* QCD */ + l_current_data += 2; + + opj_write_bytes(l_current_data,l_qcd_size-2,2); /* L_QCD */ + l_current_data += 2; + + l_remaining_size -= 4; + + if (! j2k_write_SQcd_SQcc(p_j2k,p_j2k->m_current_tile_number,0,l_current_data,&l_remaining_size,p_manager)) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error writting QCD marker\n"); + return OPJ_FALSE; + } + + if (l_remaining_size != 0) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error writting QCD marker\n"); + return OPJ_FALSE; + } + + if (opj_stream_write_data(p_stream, p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_qcd_size,p_manager) != l_qcd_size) { + return OPJ_FALSE; + } + + return OPJ_TRUE; +} + + +static void j2k_read_qcd(opj_j2k_t *j2k) { + int len, pos; + OPJ_UINT32 i; + + opj_cio_t *cio = j2k->cio; + opj_image_t *image = j2k->image; + + len = cio_read(cio, 2); /* Lqcd */ + pos = cio_tell(cio); + for (i = 0; i < image->numcomps; i++) { + cio_seek(cio, pos); + j2k_read_qcx(j2k, i, len - 2); + } +} + +/** + * Reads a QCD marker (Quantization defaults) + * @param p_header_data the data contained in the QCD box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the QCD marker. + * @param p_manager the user event manager. +*/ +opj_bool j2k_read_qcd_v2 ( + opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ) +{ + /* preconditions */ + assert(p_header_data != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + if (! j2k_read_SQcd_SQcc(p_j2k,0,p_header_data,&p_header_size,p_manager)) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading QCD marker\n"); + return OPJ_FALSE; + } + + if (p_header_size != 0) { opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading QCD marker\n"); return OPJ_FALSE; } @@ -2368,6 +3723,114 @@ static void j2k_write_qcc(opj_j2k_t *j2k, int compno) { cio_seek(cio, lenp + len); } +/** + * Writes the QCC marker (quantization component) + * + * @param p_comp_no the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +opj_bool j2k_write_qcc_v2( opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_comp_no, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) +{ + OPJ_UINT32 l_qcc_size,l_remaining_size; + + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_qcc_size = 6 + j2k_get_SQcd_SQcc_size(p_j2k,p_j2k->m_current_tile_number,p_comp_no); + l_remaining_size = l_qcc_size; + + if (l_qcc_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = (OPJ_BYTE*)opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_qcc_size); + if (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) { + return OPJ_FALSE; + } + + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_qcc_size; + } + + j2k_write_qcc_in_memory(p_j2k,p_comp_no,p_j2k->m_specific_param.m_encoder.m_header_tile_data,&l_remaining_size,p_manager); + + if (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_qcc_size,p_manager) != l_qcc_size) { + return OPJ_FALSE; + } + + return OPJ_TRUE; +} + +/** + * Writes the QCC marker (quantization component) + * + * @param p_comp_no the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +void j2k_write_qcc_in_memory( opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_comp_no, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + struct opj_event_mgr * p_manager ) +{ + OPJ_UINT32 l_qcc_size,l_remaining_size; + OPJ_BYTE * l_current_data = 00; + + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + + l_qcc_size = 6 + j2k_get_SQcd_SQcc_size(p_j2k,p_j2k->m_current_tile_number,p_comp_no); + l_remaining_size = l_qcc_size; + + l_current_data = p_data; + + opj_write_bytes(l_current_data,J2K_MS_QCC,2); /* QCC */ + l_current_data += 2; + + if (p_j2k->m_private_image->numcomps <= 256) { + --l_qcc_size; + + opj_write_bytes(l_current_data,l_qcc_size-2,2); /* L_QCC */ + l_current_data += 2; + + opj_write_bytes(l_current_data, p_comp_no, 1); /* Cqcc */ + ++l_current_data; + + /* in the case only one byte is sufficient the last byte allocated is useless -> still do -6 for available */ + l_remaining_size -= 6; + } + else { + opj_write_bytes(l_current_data,l_qcc_size-2,2); /* L_QCC */ + l_current_data += 2; + + opj_write_bytes(l_current_data, p_comp_no, 2); /* Cqcc */ + l_current_data+=2; + + l_remaining_size -= 6; + } + + j2k_write_SQcd_SQcc(p_j2k,p_j2k->m_current_tile_number,p_comp_no,l_current_data,&l_remaining_size,p_manager); + + *p_data_written = l_qcc_size; +} + +/** + * Gets the maximum size taken by a qcc. + */ +OPJ_UINT32 j2k_get_max_qcc_size (opj_j2k_v2_t *p_j2k) +{ + return j2k_get_max_coc_size(p_j2k); +} + static void j2k_read_qcc(opj_j2k_t *j2k) { int len, compno; int numcomp = j2k->image->numcomps; @@ -2451,7 +3914,7 @@ opj_bool j2k_read_qcc_v2( opj_j2k_v2_t *p_j2k, static OPJ_UINT32 backup_compno = 0; /* compno is negative or larger than the number of components!!! */ - if ((l_comp_no < 0) || (l_comp_no >= l_num_comp)) { + if (/*(l_comp_no < 0) ||*/ (l_comp_no >= l_num_comp)) { opj_event_msg_v2(p_manager, EVT_ERROR, "JPWL: bad component number in QCC (%d out of a maximum of %d)\n", l_comp_no, l_num_comp); @@ -2513,6 +3976,222 @@ static void j2k_write_poc(opj_j2k_t *j2k) { } } +/** + * Writes the POC marker (Progression Order Change) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +opj_bool j2k_write_poc_v2( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) +{ + OPJ_UINT32 l_nb_comp; + OPJ_UINT32 l_nb_poc; + OPJ_UINT32 l_poc_size; + OPJ_UINT32 l_written_size = 0; + opj_tcp_v2_t *l_tcp = 00; + opj_tccp_t *l_tccp = 00; + OPJ_UINT32 l_poc_room; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_tcp = &p_j2k->m_cp.tcps[p_j2k->m_current_tile_number]; + l_tccp = &l_tcp->tccps[0]; + l_nb_comp = p_j2k->m_private_image->numcomps; + l_nb_poc = 1 + l_tcp->numpocs; + + if (l_nb_comp <= 256) { + l_poc_room = 1; + } + else { + l_poc_room = 2; + } + l_poc_size = 4 + (5 + 2 * l_poc_room) * l_nb_poc; + + if (l_poc_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = (OPJ_BYTE*)opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_poc_size); + + if (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) { + return OPJ_FALSE; + } + + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_poc_size; + } + + j2k_write_poc_in_memory(p_j2k,p_j2k->m_specific_param.m_encoder.m_header_tile_data,&l_written_size,p_manager); + + if (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_poc_size,p_manager) != l_poc_size) { + return OPJ_FALSE; + } + + return OPJ_TRUE; +} + + +/** + * Writes the POC marker (Progression Order Change) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +void j2k_write_poc_in_memory( opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + struct opj_event_mgr * p_manager ) +{ + OPJ_UINT32 i; + OPJ_BYTE * l_current_data = 00; + OPJ_UINT32 l_nb_comp; + OPJ_UINT32 l_nb_poc; + OPJ_UINT32 l_poc_size; + opj_image_t *l_image = 00; + opj_tcp_v2_t *l_tcp = 00; + opj_tccp_t *l_tccp = 00; + opj_poc_t *l_current_poc = 00; + OPJ_UINT32 l_poc_room; + + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + + l_tcp = &p_j2k->m_cp.tcps[p_j2k->m_current_tile_number]; + l_tccp = &l_tcp->tccps[0]; + l_image = p_j2k->m_private_image; + l_nb_comp = l_image->numcomps; + l_nb_poc = 1 + l_tcp->numpocs; + + if (l_nb_comp <= 256) { + l_poc_room = 1; + } + else { + l_poc_room = 2; + } + + l_poc_size = 4 + (5 + 2 * l_poc_room) * l_nb_poc; + + l_current_data = p_data; + + opj_write_bytes(l_current_data,J2K_MS_POC,2); /* POC */ + l_current_data += 2; + + opj_write_bytes(l_current_data,l_poc_size-2,2); /* Lpoc */ + l_current_data += 2; + + l_current_poc = l_tcp->pocs; + for (i = 0; i < l_nb_poc; ++i) { + opj_write_bytes(l_current_data,l_current_poc->resno0,1); /* RSpoc_i */ + ++l_current_data; + + opj_write_bytes(l_current_data,l_current_poc->compno0,l_poc_room); /* CSpoc_i */ + l_current_data+=l_poc_room; + + opj_write_bytes(l_current_data,l_current_poc->layno1,2); /* LYEpoc_i */ + l_current_data+=2; + + opj_write_bytes(l_current_data,l_current_poc->resno1,1); /* REpoc_i */ + ++l_current_data; + + opj_write_bytes(l_current_data,l_current_poc->compno1,l_poc_room); /* CEpoc_i */ + l_current_data+=l_poc_room; + + opj_write_bytes(l_current_data,l_current_poc->prg,1); /* Ppoc_i */ + ++l_current_data; + + /* change the value of the max layer according to the actual number of layers in the file, components and resolutions*/ + l_current_poc->layno1 = int_min(l_current_poc->layno1, l_tcp->numlayers); + l_current_poc->resno1 = int_min(l_current_poc->resno1, l_tccp->numresolutions); + l_current_poc->compno1 = int_min(l_current_poc->compno1, l_nb_comp); + + ++l_current_poc; + } + + *p_data_written = l_poc_size; +} + +/** + * Gets the maximum size taken by the writing of a POC. + */ +OPJ_UINT32 j2k_get_max_poc_size(opj_j2k_v2_t *p_j2k) +{ + opj_tcp_v2_t * l_tcp = 00; + OPJ_UINT32 l_nb_tiles = 0; + OPJ_UINT32 l_max_poc = 0; + OPJ_UINT32 i; + + l_tcp = p_j2k->m_cp.tcps; + l_nb_tiles = p_j2k->m_cp.th * p_j2k->m_cp.tw; + + for (i=0;inumpocs); + ++l_tcp; + } + + ++l_max_poc; + + return 4 + 9 * l_max_poc; +} + +/** + * Gets the maximum size taken by the toc headers of all the tile parts of any given tile. + */ +OPJ_UINT32 j2k_get_max_toc_size (opj_j2k_v2_t *p_j2k) +{ + OPJ_UINT32 i; + OPJ_UINT32 l_nb_tiles; + OPJ_UINT32 l_max = 0; + opj_tcp_v2_t * l_tcp = 00; + + l_tcp = p_j2k->m_cp.tcps; + l_nb_tiles = p_j2k->m_cp.tw * p_j2k->m_cp.th ; + + for (i=0;im_nb_tile_parts); + + ++l_tcp; + } + + return 12 * l_max; +} + + +/** + * Gets the maximum size taken by the headers of the SOT. + * + * @param p_j2k the jpeg2000 codec to use. + */ +OPJ_UINT32 j2k_get_specific_header_sizes(opj_j2k_v2_t *p_j2k) +{ + OPJ_UINT32 l_nb_bytes = 0; + OPJ_UINT32 l_nb_comps; + OPJ_UINT32 l_coc_bytes,l_qcc_bytes; + + l_nb_comps = p_j2k->m_private_image->numcomps - 1; + l_nb_bytes += j2k_get_max_toc_size(p_j2k); + + if (p_j2k->m_cp.m_specific_param.m_enc.m_cinema == 0) { + l_coc_bytes = j2k_get_max_coc_size(p_j2k); + l_nb_bytes += l_nb_comps * l_coc_bytes; + + l_qcc_bytes = j2k_get_max_qcc_size(p_j2k); + l_nb_bytes += l_nb_comps * l_qcc_bytes; + } + + l_nb_bytes += j2k_get_max_poc_size(p_j2k); + + /*** DEVELOPER CORNER, Add room for your headers ***/ + + return l_nb_bytes; +} + static void j2k_read_poc(opj_j2k_t *j2k) { int len, numpchgs, i, old_poc; @@ -2652,7 +4331,7 @@ opj_bool j2k_read_crg_v2 ( ) { OPJ_UINT32 l_nb_comp; - // preconditions + /* preconditions */ assert(p_header_data != 00); assert(p_j2k != 00); assert(p_manager != 00); @@ -2711,7 +4390,7 @@ opj_bool j2k_read_tlm_v2 ( ) { OPJ_UINT32 l_Ztlm, l_Stlm, l_ST, l_SP, l_tot_num_tp, l_tot_num_tp_remaining, l_quotient, l_Ptlm_size; - // preconditions + /* preconditions */ assert(p_header_data != 00); assert(p_j2k != 00); assert(p_manager != 00); @@ -2793,7 +4472,7 @@ opj_bool j2k_read_plm_v2 ( struct opj_event_mgr * p_manager ) { - // preconditions + /* preconditions */ assert(p_header_data != 00); assert(p_j2k != 00); assert(p_manager != 00); @@ -2883,13 +4562,13 @@ opj_bool j2k_read_plt_v2 ( { OPJ_UINT32 l_Zplt, l_tmp, l_packet_len = 0, i; - // preconditions + /* preconditions */ assert(p_header_data != 00); assert(p_j2k != 00); assert(p_manager != 00); if (p_header_size < 1) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading PLM marker\n"); + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading PLT marker\n"); return OPJ_FALSE; } @@ -2900,19 +4579,19 @@ opj_bool j2k_read_plt_v2 ( for (i = 0; i < p_header_size; ++i) { opj_read_bytes(p_header_data,&l_tmp,1); /* Iplt_ij */ ++p_header_data; - // take only the last seven bytes + /* take only the last seven bytes */ l_packet_len |= (l_tmp & 0x7f); if (l_tmp & 0x80) { l_packet_len <<= 7; } else { - // store packet length and proceed to next packet + /* store packet length and proceed to next packet */ l_packet_len = 0; } } if (l_packet_len != 0) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading PLM marker\n"); + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading PLT marker\n"); return OPJ_FALSE; } @@ -2984,6 +4663,7 @@ static void j2k_read_ppm(opj_j2k_t *j2k) { * @param p_header_size the size of the data contained in the POC marker. * @param p_manager the user event manager. */ +#if 0 opj_bool j2k_read_ppm_v2 ( opj_j2k_v2_t *p_j2k, OPJ_BYTE * p_header_data, @@ -2995,7 +4675,7 @@ opj_bool j2k_read_ppm_v2 ( opj_cp_v2_t *l_cp = 00; OPJ_UINT32 l_remaining_data, l_Z_ppm, l_N_ppm; - // preconditions + /* preconditions */ assert(p_header_data != 00); assert(p_j2k != 00); assert(p_manager != 00); @@ -3012,7 +4692,7 @@ opj_bool j2k_read_ppm_v2 ( ++p_header_data; --p_header_size; - // First PPM marker + /* First PPM marker */ if (l_Z_ppm == 0) { if (p_header_size < 4) { opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading PPM marker\n"); @@ -3040,7 +4720,7 @@ opj_bool j2k_read_ppm_v2 ( while (1) { if (l_cp->ppm_data_size == l_cp->ppm_len) { if (p_header_size >= 4) { - // read a N_ppm + /* read a N_ppm */ opj_read_bytes(p_header_data,&l_N_ppm,4); /* N_ppm */ p_header_data+=4; p_header_size-=4; @@ -3080,6 +4760,7 @@ opj_bool j2k_read_ppm_v2 ( return OPJ_TRUE; } +#endif @@ -3101,12 +4782,12 @@ opj_bool j2k_read_ppm_v3 ( opj_cp_v2_t *l_cp = 00; OPJ_UINT32 l_remaining_data, l_Z_ppm, l_N_ppm; - // preconditions + /* preconditions */ assert(p_header_data != 00); assert(p_j2k != 00); assert(p_manager != 00); - // Minimum size of PPM marker is equal to the size of Zppm element + /* Minimum size of PPM marker is equal to the size of Zppm element */ if (p_header_size < 1) { opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading PPM marker\n"); return OPJ_FALSE; @@ -3119,9 +4800,9 @@ opj_bool j2k_read_ppm_v3 ( ++p_header_data; --p_header_size; - // First PPM marker + /* First PPM marker */ if (l_Z_ppm == 0) { - // We need now at least the Nppm^0 element + /* We need now at least the Nppm^0 element */ if (p_header_size < 4) { opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading PPM marker\n"); return OPJ_FALSE; @@ -3144,7 +4825,7 @@ opj_bool j2k_read_ppm_v3 ( l_cp->ppm_data_current = l_cp->ppm_data; - //l_cp->ppm_data = l_cp->ppm_buffer; + /*l_cp->ppm_data = l_cp->ppm_buffer;*/ } else { if (p_header_size < 4) { @@ -3152,9 +4833,9 @@ opj_bool j2k_read_ppm_v3 ( return OPJ_TRUE; } else { - // Uncompleted Ippm series in the previous PPM marker? + /* Uncompleted Ippm series in the previous PPM marker?*/ if (l_cp->ppm_data_read < l_cp->ppm_len) { - // Get the place where add the remaining Ippm series + /* Get the place where add the remaining Ippm series*/ l_cp->ppm_data_current = &(l_cp->ppm_data[l_cp->ppm_data_read]); l_N_ppm = l_cp->ppm_len - l_cp->ppm_data_read; } @@ -3163,10 +4844,10 @@ opj_bool j2k_read_ppm_v3 ( p_header_data+=4; p_header_size-=4; - // Increase the size of ppm_data to add the new Ippm series + /* Increase the size of ppm_data to add the new Ippm series*/ l_cp->ppm_data = (OPJ_BYTE *) opj_realloc(l_cp->ppm_data, l_cp->ppm_len + l_N_ppm); - // Keep the position of the place where concatenate the new series + /* Keep the position of the place where concatenate the new series*/ l_cp->ppm_data_current = &(l_cp->ppm_data[l_cp->ppm_len]); l_cp->ppm_len += l_N_ppm; } @@ -3176,12 +4857,12 @@ opj_bool j2k_read_ppm_v3 ( l_remaining_data = p_header_size; while (l_remaining_data >= l_N_ppm) { - // read a complete Ippm series + /* read a complete Ippm series*/ memcpy(l_cp->ppm_data_current, p_header_data, l_N_ppm); p_header_size -= l_N_ppm; p_header_data += l_N_ppm; - l_cp->ppm_data_read += l_N_ppm; // Increase the number of data read + l_cp->ppm_data_read += l_N_ppm; /* Increase the number of data read*/ if (p_header_size) { @@ -3196,39 +4877,39 @@ opj_bool j2k_read_ppm_v3 ( l_remaining_data = p_header_size; - // Next Ippm series is a complete series ? + /* Next Ippm series is a complete series ?*/ if (l_remaining_data > l_N_ppm) { - // Increase the size of ppm_data to add the new Ippm series + /* Increase the size of ppm_data to add the new Ippm series*/ l_cp->ppm_data = (OPJ_BYTE *) opj_realloc(l_cp->ppm_data, l_cp->ppm_len + l_N_ppm); - // Keep the position of the place where concatenate the new series + /* Keep the position of the place where concatenate the new series */ l_cp->ppm_data_current = &(l_cp->ppm_data[l_cp->ppm_len]); l_cp->ppm_len += l_N_ppm; } } - // Need to read an incomplete Ippm series + /* Need to read an incomplete Ippm series*/ if (l_remaining_data) { l_cp->ppm_data = (OPJ_BYTE *) opj_realloc(l_cp->ppm_data, l_cp->ppm_len + l_N_ppm); - // Keep the position of the place where concatenate the new series + /* Keep the position of the place where concatenate the new series*/ l_cp->ppm_data_current = &(l_cp->ppm_data[l_cp->ppm_len]); l_cp->ppm_len += l_N_ppm; - // Read incomplete Ippm series + /* Read incomplete Ippm series*/ memcpy(l_cp->ppm_data_current, p_header_data, l_remaining_data); p_header_size -= l_remaining_data; p_header_data += l_remaining_data; - l_cp->ppm_data_read += l_remaining_data; // Increase the number of data read + l_cp->ppm_data_read += l_remaining_data; /* Increase the number of data read*/ } #ifdef CLEAN_MSD if (l_cp->ppm_data_size == l_cp->ppm_len) { if (p_header_size >= 4) { - // read a N_ppm + /* read a N_ppm*/ opj_read_bytes(p_header_data,&l_N_ppm,4); /* N_ppm */ p_header_data+=4; p_header_size-=4; @@ -3374,6 +5055,66 @@ opj_bool j2k_read_ppt_v2 ( opj_j2k_v2_t *p_j2k, return OPJ_TRUE; } +/** + * Writes the TLM marker (Tile Length Marker) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +opj_bool j2k_write_tlm_v2( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) +{ + OPJ_BYTE * l_current_data = 00; + OPJ_UINT32 l_tlm_size; + + // 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); + + if (l_tlm_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = (OPJ_BYTE*)opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_tlm_size); + + if (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) { + return OPJ_FALSE; + } + + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_tlm_size; + } + + l_current_data = p_j2k->m_specific_param.m_encoder.m_header_tile_data; + + /* change the way data is written to avoid seeking if possible */ + // TODO + p_j2k->m_specific_param.m_encoder.m_tlm_start = opj_stream_tell(p_stream); + + opj_write_bytes(l_current_data,J2K_MS_TLM,2); /* TLM */ + l_current_data += 2; + + opj_write_bytes(l_current_data,l_tlm_size-2,2); /* Lpoc */ + l_current_data += 2; + + opj_write_bytes(l_current_data,0,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) */ + ++l_current_data; + + /* do nothing on the 5 * 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) { + return OPJ_FALSE; + } + + return OPJ_TRUE; +} + static void j2k_write_tlm(opj_j2k_t *j2k){ int lenp; opj_cio_t *cio = j2k->cio; @@ -3416,8 +5157,60 @@ static void j2k_write_sot(opj_j2k_t *j2k) { } } +/** + * Writes the SOT marker (Start of tile-part) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +opj_bool j2k_write_sot_v2( opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + const struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) +{ + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + opj_write_bytes(p_data,J2K_MS_SOT,2); /* SOT */ + p_data += 2; + + opj_write_bytes(p_data,10,2); /* Lsot */ + p_data += 2; + + opj_write_bytes(p_data, p_j2k->m_current_tile_number,2); /* Isot */ + p_data += 2; + + /* Psot */ + p_data += 4; + + opj_write_bytes(p_data, p_j2k->m_specific_param.m_encoder.m_current_tile_part_number,1); /* TPsot */ + ++p_data; + + opj_write_bytes(p_data, p_j2k->m_cp.tcps[p_j2k->m_current_tile_number].m_nb_tile_parts,1); /* TNsot */ + ++p_data; + + /* UniPG>> */ +#ifdef USE_JPWL + /* update markers struct */ +/* + j2k_add_marker(p_j2k->cstr_info, J2K_MS_SOT, p_j2k->sot_start, len + 2); +*/ + assert( 0 && "TODO" ); +#endif /* USE_JPWL */ + + * p_data_written = 12; + + return OPJ_TRUE; +} + + static void j2k_read_sot(opj_j2k_t *j2k) { - int len, tileno, totlen, partno, numparts, i; + int len, tileno, totlen, partno, numparts; + OPJ_UINT32 i; opj_tcp_t *tcp = NULL; char status = 0; @@ -3433,7 +5226,7 @@ static void j2k_read_sot(opj_j2k_t *j2k) { static int backup_tileno = 0; /* tileno is negative or larger than the number of tiles!!! */ - if ((tileno < 0) || (tileno > (cp->tw * cp->th))) { + if ((tileno < 0) || (tileno >= (cp->tw * cp->th))) { opj_event_msg(j2k->cinfo, EVT_ERROR, "JPWL: bad tile number (%d out of a maximum of %d)\n", tileno, (cp->tw * cp->th)); @@ -3450,15 +5243,26 @@ static void j2k_read_sot(opj_j2k_t *j2k) { /* keep your private count of tiles */ backup_tileno++; - }; + } + else #endif /* USE_JPWL */ + { + /* tileno is negative or larger than the number of tiles!!! */ + if ((tileno < 0) || (tileno >= (cp->tw * cp->th))) { + opj_event_msg(j2k->cinfo, EVT_ERROR, + "JPWL: bad tile number (%d out of a maximum of %d)\n", + tileno, (cp->tw * cp->th)); + return; + } + } if (cp->tileno_size == 0) { cp->tileno[cp->tileno_size] = tileno; cp->tileno_size++; } else { i = 0; - while (i < cp->tileno_size && status == 0) { + assert(cp->tileno_size >= 0); + while (i < (OPJ_UINT32)cp->tileno_size && status == 0) { status = cp->tileno[i] == tileno ? 1 : 0; i++; } @@ -3489,8 +5293,18 @@ static void j2k_read_sot(opj_j2k_t *j2k) { totlen); } - }; + } + else #endif /* USE_JPWL */ + { + /* totlen is negative or larger than the bytes left!!! */ + if ((totlen < 0) || (totlen > (cio_numbytesleft(cio) + 8))) { + opj_event_msg(j2k->cinfo, EVT_ERROR, + "JPWL: bad tile byte size (%d bytes against %d bytes left)\n", + totlen, cio_numbytesleft(cio) + 8); + return; + } + } if (!totlen) totlen = cio_numbytesleft(cio) + 8; @@ -3524,7 +5338,7 @@ static void j2k_read_sot(opj_j2k_t *j2k) { if (numparts) j2k->cstr_info->tile[tileno].tp = (opj_tp_info_t *) opj_realloc(j2k->cstr_info->tile[tileno].tp, numparts * sizeof(opj_tp_info_t)); else - j2k->cstr_info->tile[tileno].tp = (opj_tp_info_t *) opj_realloc(j2k->cstr_info->tile[tileno].tp, 10 * sizeof(opj_tp_info_t)); // Fixme (10) + j2k->cstr_info->tile[tileno].tp = (opj_tp_info_t *) opj_realloc(j2k->cstr_info->tile[tileno].tp, 10 * sizeof(opj_tp_info_t)); /* Fixme (10)*/ j2k->cstr_info->tile[tileno].tp[partno].tp_start_pos = cio_tell(cio) - 12; j2k->cstr_info->tile[tileno].tp[partno].tp_end_pos = j2k->cstr_info->tile[tileno].tp[partno].tp_start_pos + totlen - 1; @@ -3621,11 +5435,19 @@ opj_bool j2k_read_sot_v2 ( opj_read_bytes(p_header_data,&l_tot_len,4); /* Psot */ p_header_data+=4; + /* PSot should be equal to zero or >=14 or <= 2^32-1 */ + if ((l_tot_len !=0 ) && (l_tot_len < 14) ) + { + opj_event_msg_v2(p_manager, EVT_ERROR, "Psot value (%d) is not correct regards to the JPEG2000 norm!\n", l_tot_len); + return OPJ_FALSE; + } + + #ifdef USE_JPWL if (l_cp->correct) { /* totlen is negative or larger than the bytes left!!! */ - if ((l_tot_len < 0) || (l_tot_len > p_header_size ) ) { /* FIXME it seems correct; for info in V1 -> (p_stream_numbytesleft(p_stream) + 8))) { */ + if (/*(l_tot_len < 0) ||*/ (l_tot_len > p_header_size ) ) { /* FIXME it seems correct; for info in V1 -> (p_stream_numbytesleft(p_stream) + 8))) { */ opj_event_msg_v2(p_manager, EVT_ERROR, "JPWL: bad tile byte size (%d bytes against %d bytes left)\n", l_tot_len, p_header_size ); /* FIXME it seems correct; for info in V1 -> p_stream_numbytesleft(p_stream) + 8); */ @@ -3695,13 +5517,16 @@ opj_bool j2k_read_sot_v2 ( || (l_tile_y < p_j2k->m_specific_param.m_decoder.m_start_tile_y) || (l_tile_y >= p_j2k->m_specific_param.m_decoder.m_end_tile_y); } - else - p_j2k->m_specific_param.m_decoder.m_skip_data = - (p_j2k->m_current_tile_number != p_j2k->m_specific_param.m_decoder.m_tile_ind_to_dec); + else { + assert( p_j2k->m_specific_param.m_decoder.m_tile_ind_to_dec >= 0 ); + p_j2k->m_specific_param.m_decoder.m_skip_data = + (p_j2k->m_current_tile_number != (OPJ_UINT32)p_j2k->m_specific_param.m_decoder.m_tile_ind_to_dec); + } /* Index */ if (p_j2k->cstr_index) { + assert(p_j2k->cstr_index->tile_index != 00); p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tileno = p_j2k->m_current_tile_number; p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].current_tpsno = l_current_part; @@ -3846,6 +5671,97 @@ static void j2k_write_sod(opj_j2k_t *j2k, void *tile_coder) { cio_seek(cio, j2k->sot_start + totlen); } +/** + * Writes the SOD marker (Start of data) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +opj_bool j2k_write_sod_v2( opj_j2k_v2_t *p_j2k, + struct opj_tcd_v2 * p_tile_coder, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 p_total_data_size, + const struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) +{ + opj_tcp_v2_t *l_tcp = 00; + opj_codestream_info_t *l_cstr_info = 00; + opj_cp_v2_t *l_cp = 00; + + OPJ_UINT32 l_size_tile; + OPJ_UINT32 l_remaining_data; + + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + 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_cp = &(p_j2k->m_cp); + l_tcp = &l_cp->tcps[p_j2k->m_current_tile_number]; + + + /* update tile coder */ + p_tile_coder->tp_num = p_j2k->m_specific_param.m_encoder.m_current_poc_tile_part_number ; + p_tile_coder->cur_tp_num = p_j2k->m_specific_param.m_encoder.m_current_tile_part_number; + + l_size_tile = l_cp->th * l_cp->tw; + + /* INDEX >> */ + /* TODO mergeV2: check this part which use cstr_info */ + /*l_cstr_info = p_j2k->cstr_info; + if (l_cstr_info) { + if (!p_j2k->m_specific_param.m_encoder.m_current_tile_part_number ) { + //TODO cstr_info->tile[p_j2k->m_current_tile_number].end_header = p_stream_tell(p_stream) + p_j2k->pos_correction - 1; + l_cstr_info->tile[p_j2k->m_current_tile_number].tileno = p_j2k->m_current_tile_number; + } + else {*/ + /* + TODO + if + (cstr_info->tile[p_j2k->m_current_tile_number].packet[cstr_info->packno - 1].end_pos < p_stream_tell(p_stream)) + { + cstr_info->tile[p_j2k->m_current_tile_number].packet[cstr_info->packno].start_pos = p_stream_tell(p_stream); + }*/ + /*}*/ + /* UniPG>> */ +#ifdef USE_JPWL + /* update markers struct */ + /*j2k_add_marker(p_j2k->cstr_info, J2K_MS_SOD, p_j2k->sod_start, 2); +*/ + assert( 0 && "TODO" ); +#endif /* USE_JPWL */ + /* <m_specific_param.m_encoder.m_current_tile_part_number == 0) { + p_tile_coder->tcd_image->tiles->packno = 0; + if (l_cstr_info) { + l_cstr_info->packno = 0; + } + } + + *p_data_written = 0; + + if (! tcd_encode_tile_v2(p_tile_coder, p_j2k->m_current_tile_number, p_data, p_data_written, l_remaining_data , l_cstr_info)) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Cannot encode tile\n"); + return OPJ_FALSE; + } + + *p_data_written += 2; + + return OPJ_TRUE; +} + + static void j2k_read_sod(opj_j2k_t *j2k) { int len, truncate = 0, i; unsigned char *data = NULL, *data_ptr = NULL; @@ -3915,10 +5831,10 @@ opj_bool j2k_read_sod_v2 ( l_tcp = &(p_j2k->m_cp.tcps[p_j2k->m_current_tile_number]); if (p_j2k->m_specific_param.m_decoder.m_last_tile_part) { - // opj_stream_get_number_byte_left returns OPJ_OFF_T + /* opj_stream_get_number_byte_left returns OPJ_OFF_T // but we are in the last tile part, // so its result will fit on OPJ_UINT32 unless we find - // a file with a single tile part of more than 4 GB... + // a file with a single tile part of more than 4 GB...*/ p_j2k->m_specific_param.m_decoder.m_sot_length = (OPJ_UINT32)(opj_stream_get_number_byte_left(p_stream) - 2); } else @@ -3991,6 +5907,74 @@ static void j2k_write_rgn(opj_j2k_t *j2k, int compno, int tileno) { cio_write(cio, tcp->tccps[compno].roishift, 1); /* SPrgn */ } +/** + * Writes the RGN marker (Region Of Interest) + * + * @param p_tile_no the tile to output + * @param p_comp_no the component to output + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +opj_bool j2k_write_rgn_v2( opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) +{ + OPJ_BYTE * l_current_data = 00; + OPJ_UINT32 l_nb_comp; + OPJ_UINT32 l_rgn_size; + opj_image_t *l_image = 00; + opj_cp_v2_t *l_cp = 00; + opj_tcp_v2_t *l_tcp = 00; + opj_tccp_t *l_tccp = 00; + OPJ_UINT32 l_comp_room; + + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_cp = &(p_j2k->m_cp); + l_tcp = &l_cp->tcps[p_tile_no]; + l_tccp = &l_tcp->tccps[p_comp_no]; + + l_nb_comp = l_image->numcomps; + + if (l_nb_comp <= 256) { + l_comp_room = 1; + } + else { + l_comp_room = 2; + } + + l_rgn_size = 6 + l_comp_room; + + l_current_data = p_j2k->m_specific_param.m_encoder.m_header_tile_data; + + opj_write_bytes(l_current_data,J2K_MS_RGN,2); /* RGN */ + l_current_data += 2; + + opj_write_bytes(l_current_data,l_rgn_size-2,2); /* Lrgn */ + l_current_data += 2; + + opj_write_bytes(l_current_data,p_comp_no,l_comp_room); /* Crgn */ + l_current_data+=l_comp_room; + + opj_write_bytes(l_current_data, 0,1); /* Srgn */ + ++l_current_data; + + opj_write_bytes(l_current_data, l_tccp->roishift,1); /* SPrgn */ + ++l_current_data; + + if (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_rgn_size,p_manager) != l_rgn_size) { + return OPJ_FALSE; + } + + return OPJ_TRUE; +} + static void j2k_read_rgn(opj_j2k_t *j2k) { int len, compno, roisty; @@ -4034,6 +6018,45 @@ static void j2k_write_eoc(opj_j2k_t *j2k) { /* <m_specific_param.m_encoder.m_header_tile_data,J2K_MS_EOC,2); /* EOC */ + + +/* UniPG>> */ +#ifdef USE_JPWL + /* update markers struct */ + /* + j2k_add_marker(p_j2k->cstr_info, J2K_MS_EOC, p_stream_tell(p_stream) - 2, 2); +*/ +#endif /* USE_JPWL */ + + if ( opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,2,p_manager) != 2) { + return OPJ_FALSE; + } + + if ( ! opj_stream_flush(p_stream,p_manager) ) { + return OPJ_FALSE; + } + + return OPJ_TRUE; +} + + /** * Reads a RGN marker (Region Of Interest) * @@ -4056,7 +6079,7 @@ opj_bool j2k_read_rgn_v2 ( opj_tcp_v2_t *l_tcp = 00; OPJ_UINT32 l_comp_room, l_comp_no, l_roi_sty; - // preconditions + /* preconditions*/ assert(p_header_data != 00); assert(p_j2k != 00); assert(p_manager != 00); @@ -4106,4389 +6129,6677 @@ opj_bool j2k_read_rgn_v2 ( } -static void j2k_read_eoc(opj_j2k_t *j2k) { - int i, tileno; - opj_bool success; +static OPJ_FLOAT32 get_tp_stride (opj_tcp_v2_t * p_tcp) +{ + return (OPJ_FLOAT32) ((p_tcp->m_nb_tile_parts - 1) * 14); +} - /* if packets should be decoded */ - if (j2k->cp->limit_decoding != DECODE_ALL_BUT_PACKETS) { - opj_tcd_t *tcd = tcd_create(j2k->cinfo); - tcd_malloc_decode(tcd, j2k->image, j2k->cp); - for (i = 0; i < j2k->cp->tileno_size; i++) { - tcd_malloc_decode_tile(tcd, j2k->image, j2k->cp, i, j2k->cstr_info); - tileno = j2k->cp->tileno[i]; - success = tcd_decode_tile(tcd, j2k->tile_data[tileno], j2k->tile_len[tileno], tileno, j2k->cstr_info); - opj_free(j2k->tile_data[tileno]); - j2k->tile_data[tileno] = NULL; - tcd_free_decode_tile(tcd, i); - if (success == OPJ_FALSE) { - j2k->state |= J2K_STATE_ERR; - break; - } - } - tcd_free_decode(tcd); - tcd_destroy(tcd); - } - /* if packets should not be decoded */ - else { - for (i = 0; i < j2k->cp->tileno_size; i++) { - tileno = j2k->cp->tileno[i]; - opj_free(j2k->tile_data[tileno]); - j2k->tile_data[tileno] = NULL; - } - } - if (j2k->state & J2K_STATE_ERR) - j2k->state = J2K_STATE_MT + J2K_STATE_ERR; - else - j2k->state = J2K_STATE_MT; +static OPJ_FLOAT32 get_default_stride (opj_tcp_v2_t * p_tcp) +{ + (void)p_tcp; + return 0; } /** - * Reads a EOC marker (End Of Codestream) + * Updates the rates of the tcp. * - * @param p_header_data the data contained in the SOD box. - * @param p_j2k the jpeg2000 codec. - * @param p_header_size the size of the data contained in the SOD marker. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. * @param p_manager the user event manager. */ -opj_bool j2k_read_eoc_v2 ( opj_j2k_v2_t *p_j2k, +opj_bool j2k_update_rates( opj_j2k_v2_t *p_j2k, struct opj_stream_private *p_stream, struct opj_event_mgr * p_manager ) { - OPJ_UINT32 i; - opj_tcd_v2_t * l_tcd = 00; - OPJ_UINT32 l_nb_tiles; + opj_cp_v2_t * l_cp = 00; + opj_image_t * l_image = 00; opj_tcp_v2_t * l_tcp = 00; - opj_bool l_success; + opj_image_comp_t * l_img_comp = 00; + + OPJ_UINT32 i,j,k; + OPJ_INT32 l_x0,l_y0,l_x1,l_y1; + 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_UINT32 l_last_res; + OPJ_FLOAT32 (* l_tp_stride_func)(opj_tcp_v2_t *) = 00; /* preconditions */ assert(p_j2k != 00); assert(p_manager != 00); assert(p_stream != 00); - l_nb_tiles = p_j2k->m_cp.th * p_j2k->m_cp.tw; - l_tcp = p_j2k->m_cp.tcps; - l_tcd = tcd_create_v2(OPJ_TRUE); - if (l_tcd == 00) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Cannot decode tile, memory error\n"); - return OPJ_FALSE; + l_cp = &(p_j2k->m_cp); + l_image = p_j2k->m_private_image; + l_tcp = l_cp->tcps; + + l_bits_empty = 8 * l_image->comps->dx * l_image->comps->dy; + l_size_pixel = l_image->numcomps * l_image->comps->prec; + l_sot_remove = ((OPJ_FLOAT32) opj_stream_tell(p_stream)) / (l_cp->th * l_cp->tw); + + if (l_cp->m_specific_param.m_enc.m_tp_on) { + l_tp_stride_func = get_tp_stride; + } + else { + l_tp_stride_func = get_default_stride; } - for (i = 0; i < l_nb_tiles; ++i) { - if (l_tcp->m_data) { - if (! tcd_init_decode_tile(l_tcd, i)) { - tcd_destroy_v2(l_tcd); - opj_event_msg_v2(p_manager, EVT_ERROR, "Cannot decode tile, memory error\n"); - return OPJ_FALSE; + for (i=0;ith;++i) { + for (j=0;jtw;++j) { + OPJ_FLOAT32 l_offset = ((*l_tp_stride_func)(l_tcp)) / l_tcp->numlayers; + + /* 4 borders of the tile rescale on the image if necessary */ + l_x0 = int_max(l_cp->tx0 + j * l_cp->tdx, l_image->x0); + l_y0 = int_max(l_cp->ty0 + i * l_cp->tdy, l_image->y0); + l_x1 = int_min(l_cp->tx0 + (j + 1) * l_cp->tdx, l_image->x1); + l_y1 = int_min(l_cp->ty0 + (i + 1) * l_cp->tdy, l_image->y1); + + l_rates = l_tcp->rates; + + /* Modification of the RATE >> */ + if (*l_rates) { + *l_rates = (( (float) (l_size_pixel * (l_x1 - l_x0) * (l_y1 - l_y0))) + / + ((*l_rates) * l_bits_empty) + ) + - + l_offset; } - l_success = tcd_decode_tile_v2(l_tcd, l_tcp->m_data, l_tcp->m_data_size, i, p_j2k->cstr_index); - /* cleanup */ + ++l_rates; - if (! l_success) { - p_j2k->m_specific_param.m_decoder.m_state |= J2K_STATE_ERR; - break; + for (k = 1; k < l_tcp->numlayers; ++k) { + if (*l_rates) { + *l_rates = (( (OPJ_FLOAT32) (l_size_pixel * (l_x1 - l_x0) * (l_y1 - l_y0))) + / + ((*l_rates) * l_bits_empty) + ) + - + l_offset; + } + + ++l_rates; } - } - j2k_tcp_destroy(l_tcp); - ++l_tcp; + ++l_tcp; + + } } - tcd_destroy_v2(l_tcd); - return OPJ_TRUE; -} + l_tcp = l_cp->tcps; -typedef struct opj_dec_mstabent { - /** marker value */ - int id; - /** value of the state when the marker can appear */ - int states; - /** action linked to the marker */ - void (*handler) (opj_j2k_t *j2k); -} opj_dec_mstabent_t; + for (i=0;ith;++i) { + for (j=0;jtw;++j) { + l_rates = l_tcp->rates; -opj_dec_mstabent_t j2k_dec_mstab[] = { - {J2K_MS_SOC, J2K_STATE_MHSOC, j2k_read_soc}, - {J2K_MS_SOT, J2K_STATE_MH | J2K_STATE_TPHSOT, j2k_read_sot}, - {J2K_MS_SOD, J2K_STATE_TPH, j2k_read_sod}, - {J2K_MS_EOC, J2K_STATE_TPHSOT, j2k_read_eoc}, - {J2K_MS_SIZ, J2K_STATE_MHSIZ, j2k_read_siz}, - {J2K_MS_COD, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_cod}, - {J2K_MS_COC, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_coc}, - {J2K_MS_RGN, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_rgn}, - {J2K_MS_QCD, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_qcd}, - {J2K_MS_QCC, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_qcc}, - {J2K_MS_POC, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_poc}, - {J2K_MS_TLM, J2K_STATE_MH, j2k_read_tlm}, - {J2K_MS_PLM, J2K_STATE_MH, j2k_read_plm}, - {J2K_MS_PLT, J2K_STATE_TPH, j2k_read_plt}, - {J2K_MS_PPM, J2K_STATE_MH, j2k_read_ppm}, - {J2K_MS_PPT, J2K_STATE_TPH, j2k_read_ppt}, - {J2K_MS_SOP, 0, 0}, - {J2K_MS_CRG, J2K_STATE_MH, j2k_read_crg}, - {J2K_MS_COM, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_com}, + if (*l_rates) { + *l_rates -= l_sot_remove; -#ifdef USE_JPWL - {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}, - {J2K_MS_RED, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_red}, -#endif /* USE_JPWL */ -#ifdef USE_JPSEC - {J2K_MS_SEC, J2K_STATE_MH, j2k_read_sec}, - {J2K_MS_INSEC, 0, j2k_read_insec}, -#endif /* USE_JPSEC */ + if (*l_rates < 30) { + *l_rates = 30; + } + } - {0, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_unk} -}; + ++l_rates; -static void j2k_read_unk(opj_j2k_t *j2k) { - opj_event_msg(j2k->cinfo, EVT_WARNING, "Unknown marker\n"); + l_last_res = l_tcp->numlayers - 1; -#ifdef USE_JPWL - if (j2k->cp->correct) { - int m = 0, id, i; - int min_id = 0, min_dist = 17, cur_dist = 0, tmp_id; - cio_seek(j2k->cio, cio_tell(j2k->cio) - 2); - id = cio_read(j2k->cio, 2); - opj_event_msg(j2k->cinfo, EVT_ERROR, - "JPWL: really don't know this marker %x\n", - id); - if (!JPWL_ASSUME) { - opj_event_msg(j2k->cinfo, EVT_ERROR, - "- possible synch loss due to uncorrectable codestream errors => giving up\n"); - return; - } - /* OK, activate this at your own risk!!! */ - /* we look for the marker at the minimum hamming distance from this */ - while (j2k_dec_mstab[m].id) { - - /* 1's where they differ */ - tmp_id = j2k_dec_mstab[m].id ^ id; + for (k = 1; k < l_last_res; ++k) { - /* compute the hamming distance between our id and the current */ - cur_dist = 0; - for (i = 0; i < 16; i++) { - if ((tmp_id >> i) & 0x0001) { - cur_dist++; + if (*l_rates) { + *l_rates -= l_sot_remove; + + if (*l_rates < *(l_rates - 1) + 10) { + *l_rates = (*(l_rates - 1)) + 20; + } } + + ++l_rates; } - /* if current distance is smaller, set the minimum */ - if (cur_dist < min_dist) { - min_dist = cur_dist; - min_id = j2k_dec_mstab[m].id; + if (*l_rates) { + *l_rates -= (l_sot_remove + 2.f); + + if (*l_rates < *(l_rates - 1) + 10) { + *l_rates = (*(l_rates - 1)) + 20; + } } - - /* jump to the next marker */ - m++; + + ++l_tcp; } + } - /* do we substitute the marker? */ - if (min_dist < JPWL_MAXIMUM_HAMMING) { - opj_event_msg(j2k->cinfo, EVT_ERROR, - "- marker %x is at distance %d from the read %x\n", - min_id, min_dist, id); - opj_event_msg(j2k->cinfo, EVT_ERROR, - "- trying to substitute in place and crossing fingers!\n"); - cio_seek(j2k->cio, cio_tell(j2k->cio) - 2); - cio_write(j2k->cio, min_id, 2); + l_img_comp = l_image->comps; + l_tile_size = 0; - /* rewind */ - cio_seek(j2k->cio, cio_tell(j2k->cio) - 2); + for (i=0;inumcomps;++i) { + l_tile_size += ( uint_ceildiv(l_cp->tdx,l_img_comp->dx) + * + uint_ceildiv(l_cp->tdy,l_img_comp->dy) + * + l_img_comp->prec + ); + + ++l_img_comp; + } + + l_tile_size = (OPJ_UINT32) (l_tile_size * 0.1625); /* 1.3/8 = 0.1625 */ + + l_tile_size += j2k_get_specific_header_sizes(p_j2k); + + p_j2k->m_specific_param.m_encoder.m_encoded_tile_size = 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) { + return OPJ_FALSE; + } + if (l_cp->m_specific_param.m_enc.m_cinema) { + p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer = + (OPJ_BYTE *) opj_malloc(5*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; } - }; -#endif /* USE_JPWL */ + p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current = + p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer; + } + + return OPJ_TRUE; +} + +static void j2k_read_eoc(opj_j2k_t *j2k) { + int i, tileno; + opj_bool success = OPJ_FALSE; + /* if packets should be decoded */ + if (j2k->cp->limit_decoding != DECODE_ALL_BUT_PACKETS) { + opj_tcd_t *tcd = tcd_create(j2k->cinfo); + tcd_malloc_decode(tcd, j2k->image, j2k->cp); + for (i = 0; i < j2k->cp->tileno_size; i++) { + tcd_malloc_decode_tile(tcd, j2k->image, j2k->cp, i, j2k->cstr_info); + if (j2k->cp->tileno[i] != -1) + { + tileno = j2k->cp->tileno[i]; + success = tcd_decode_tile(tcd, j2k->tile_data[tileno], j2k->tile_len[tileno], tileno, j2k->cstr_info); + opj_free(j2k->tile_data[tileno]); + j2k->tile_data[tileno] = NULL; + tcd_free_decode_tile(tcd, i); + } + else + success = OPJ_FALSE; + if (success == OPJ_FALSE) { + j2k->state |= J2K_STATE_ERR; + break; + } + } + tcd_free_decode(tcd); + tcd_destroy(tcd); + } + /* if packets should not be decoded */ + else { + for (i = 0; i < j2k->cp->tileno_size; i++) { + tileno = j2k->cp->tileno[i]; + opj_free(j2k->tile_data[tileno]); + j2k->tile_data[tileno] = NULL; + } + } + if (j2k->state & J2K_STATE_ERR) + j2k->state = J2K_STATE_MT + J2K_STATE_ERR; + else + j2k->state = J2K_STATE_MT; } /** - * Reads an unknown marker + * Reads a EOC marker (End Of Codestream) * - * @param p_stream the stream object to read from. + * @param p_header_data the data contained in the SOD box. * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the SOD marker. * @param p_manager the user event manager. - * - * @return true if the marker could be deduced. */ -opj_bool j2k_read_unk_v2 ( opj_j2k_v2_t *p_j2k, +#if 0 +opj_bool j2k_read_eoc_v2 ( opj_j2k_v2_t *p_j2k, struct opj_stream_private *p_stream, - OPJ_UINT32 *output_marker, - struct opj_event_mgr * p_manager - ) + struct opj_event_mgr * p_manager ) { - OPJ_UINT32 l_unknown_marker; - const opj_dec_memory_marker_handler_t * l_marker_handler; - OPJ_UINT32 l_size_unk = 2; + OPJ_UINT32 i; + opj_tcd_v2_t * l_tcd = 00; + OPJ_UINT32 l_nb_tiles; + opj_tcp_v2_t * l_tcp = 00; + opj_bool l_success; - // preconditions + /* preconditions */ assert(p_j2k != 00); assert(p_manager != 00); assert(p_stream != 00); - opj_event_msg_v2(p_manager, EVT_WARNING, "Unknown marker\n"); - - while(1) { - // 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_v2(p_manager, EVT_ERROR, "Stream too short\n"); - return OPJ_FALSE; - } - - // read 2 bytes as the new marker ID - opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data,&l_unknown_marker,2); - - if (!(l_unknown_marker < 0xff00)) { + l_nb_tiles = p_j2k->m_cp.th * p_j2k->m_cp.tw; + l_tcp = p_j2k->m_cp.tcps; - // Get the marker handler from the marker ID - l_marker_handler = j2k_get_marker_handler(l_unknown_marker); + l_tcd = tcd_create_v2(OPJ_TRUE); + if (l_tcd == 00) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Cannot decode tile, memory error\n"); + return OPJ_FALSE; + } - if (!(p_j2k->m_specific_param.m_decoder.m_state & l_marker_handler->states)) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Marker is not compliant with its position\n"); + for (i = 0; i < l_nb_tiles; ++i) { + if (l_tcp->m_data) { + if (! tcd_init_decode_tile(l_tcd, i)) { + tcd_destroy_v2(l_tcd); + opj_event_msg_v2(p_manager, EVT_ERROR, "Cannot decode tile, memory error\n"); return OPJ_FALSE; } - else { - if (l_marker_handler->id != J2K_MS_UNK) { - /* Add the marker to the codestream index*/ - if (l_marker_handler->id != J2K_MS_SOT) - j2k_add_mhmarker_v2(p_j2k->cstr_index, J2K_MS_UNK, - (OPJ_UINT32) opj_stream_tell(p_stream) - l_size_unk, - l_size_unk); - break; /* next marker is known and well located */ - } - else - l_size_unk += 2; + + l_success = tcd_decode_tile_v2(l_tcd, l_tcp->m_data, l_tcp->m_data_size, i, p_j2k->cstr_index); + /* cleanup */ + + if (! l_success) { + p_j2k->m_specific_param.m_decoder.m_state |= J2K_STATE_ERR; + break; } } - } - *output_marker = l_marker_handler->id ; + j2k_tcp_destroy(l_tcp); + ++l_tcp; + } + tcd_destroy_v2(l_tcd); return OPJ_TRUE; } +#endif /** -Read the lookup table containing all the marker, status and action -@param id Marker value + * Gets the offset of the header. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. */ -static opj_dec_mstabent_t *j2k_dec_mstab_lookup(int id) { - opj_dec_mstabent_t *e; - for (e = j2k_dec_mstab; e->id != 0; e++) { - if (e->id == id) { - break; - } - } - return e; -} +opj_bool j2k_get_end_header(opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) +{ + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + p_j2k->cstr_index->main_head_end = opj_stream_tell(p_stream); + + return OPJ_TRUE; +} /** - * Reads a MCT marker (Multiple Component Transform) + * Writes the MCT marker (Multiple Component Transform) * - * @param p_header_data the data contained in the MCT box. - * @param p_j2k the jpeg2000 codec. - * @param p_header_size the size of the data contained in the MCT marker. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. * @param p_manager the user event manager. */ -opj_bool j2k_read_mct ( opj_j2k_v2_t *p_j2k, - OPJ_BYTE * p_header_data, - OPJ_UINT32 p_header_size, - struct opj_event_mgr * p_manager ) +opj_bool j2k_write_mct_data_group( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) { OPJ_UINT32 i; - opj_tcp_v2_t *l_tcp = 00; - OPJ_UINT32 l_tmp; - OPJ_UINT32 l_indix; - opj_mct_data_t * l_mct_data; + opj_simple_mcc_decorrelation_data_t * l_mcc_record; + opj_mct_data_t * l_mct_record; + opj_tcp_v2_t * l_tcp; /* preconditions */ - assert(p_header_data != 00); assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); - l_tcp = p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_TPH ? - &p_j2k->m_cp.tcps[p_j2k->m_current_tile_number] : - p_j2k->m_specific_param.m_decoder.m_default_tcp; - - if (p_header_size < 2) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCT marker\n"); - return OPJ_FALSE; - } - - /* first marker */ - opj_read_bytes(p_header_data,&l_tmp,2); /* Zmct */ - p_header_data += 2; - if (l_tmp != 0) { - opj_event_msg_v2(p_manager, EVT_WARNING, "Cannot take in charge mct data within multiple MCT records\n"); - return OPJ_TRUE; - } - - if(p_header_size <= 6) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCT marker\n"); + if (! j2k_write_cbd(p_j2k,p_stream,p_manager)) { return OPJ_FALSE; } - /* Imct -> no need for other values, take the first, type is double with decorrelation x0000 1101 0000 0000*/ - opj_read_bytes(p_header_data,&l_tmp,2); /* Imct */ - p_header_data += 2; - - l_indix = l_tmp & 0xff; - l_mct_data = l_tcp->m_mct_records; + l_tcp = &(p_j2k->m_cp.tcps[p_j2k->m_current_tile_number]); + l_mct_record = l_tcp->m_mct_records; for (i=0;im_nb_mct_records;++i) { - if (l_mct_data->m_index == l_indix) { - break; - } - ++l_mct_data; - } - - /* NOT FOUND */ - if (i == l_tcp->m_nb_mct_records) { - if (l_tcp->m_nb_mct_records == l_tcp->m_nb_max_mct_records) { - l_tcp->m_nb_max_mct_records += J2K_MCT_DEFAULT_NB_RECORDS; - - l_tcp->m_mct_records = (opj_mct_data_t*)opj_realloc(l_tcp->m_mct_records,l_tcp->m_nb_max_mct_records * sizeof(opj_mct_data_t)); - if(! l_tcp->m_mct_records) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCT marker\n"); - return OPJ_FALSE; - } - l_mct_data = l_tcp->m_mct_records + l_tcp->m_nb_mct_records; - memset(l_mct_data ,0,(l_tcp->m_nb_max_mct_records - l_tcp->m_nb_mct_records) * sizeof(opj_mct_data_t)); + if (! j2k_write_mct_record(p_j2k,l_mct_record,p_stream,p_manager)) { + return OPJ_FALSE; } - l_mct_data = l_tcp->m_mct_records + l_tcp->m_nb_mct_records; + ++l_mct_record; } - if (l_mct_data->m_data) { - opj_free(l_mct_data->m_data); - l_mct_data->m_data = 00; - } + l_mcc_record = l_tcp->m_mcc_records; - l_mct_data->m_index = l_indix; - l_mct_data->m_array_type = (J2K_MCT_ARRAY_TYPE)((l_tmp >> 8) & 3); - l_mct_data->m_element_type = (J2K_MCT_ELEMENT_TYPE)((l_tmp >> 10) & 3); + for (i=0;im_nb_mcc_records;++i) { - opj_read_bytes(p_header_data,&l_tmp,2); /* Ymct */ - p_header_data+=2; - if (l_tmp != 0) { - opj_event_msg_v2(p_manager, EVT_WARNING, "Cannot take in charge multiple MCT markers\n"); - return OPJ_TRUE; - } + if (! j2k_write_mcc_record(p_j2k,l_mcc_record,p_stream,p_manager)) { + return OPJ_FALSE; + } - p_header_size -= 6; + ++l_mcc_record; + } - l_mct_data->m_data = (OPJ_BYTE*)opj_malloc(p_header_size); - if (! l_mct_data->m_data) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCT marker\n"); + if (! j2k_write_mco(p_j2k,p_stream,p_manager)) { return OPJ_FALSE; } - memcpy(l_mct_data->m_data,p_header_data,p_header_size); - - l_mct_data->m_data_size = p_header_size; - ++l_tcp->m_nb_mct_records; return OPJ_TRUE; } /** - * Reads a MCC marker (Multiple Component Collection) + * Writes the image components. * - * @param p_header_data the data contained in the MCC box. - * @param p_j2k the jpeg2000 codec. - * @param p_header_size the size of the data contained in the MCC marker. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. * @param p_manager the user event manager. */ -opj_bool j2k_read_mcc ( opj_j2k_v2_t *p_j2k, - OPJ_BYTE * p_header_data, - OPJ_UINT32 p_header_size, - struct opj_event_mgr * p_manager ) +opj_bool j2k_write_image_components(opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) { - OPJ_UINT32 i,j; - OPJ_UINT32 l_tmp; - OPJ_UINT32 l_indix; - opj_tcp_v2_t * l_tcp; - opj_simple_mcc_decorrelation_data_t * l_mcc_record; - opj_mct_data_t * l_mct_data; - OPJ_UINT32 l_nb_collections; - OPJ_UINT32 l_nb_comps; - OPJ_UINT32 l_nb_bytes_by_comp; - + OPJ_UINT32 compno; /* preconditions */ - assert(p_header_data != 00); assert(p_j2k != 00); assert(p_manager != 00); + assert(p_stream != 00); - l_tcp = p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_TPH ? - &p_j2k->m_cp.tcps[p_j2k->m_current_tile_number] : - p_j2k->m_specific_param.m_decoder.m_default_tcp; - - if (p_header_size < 2) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCC marker\n"); - return OPJ_FALSE; - } + for (compno = 1; compno < p_j2k->m_private_image->numcomps; ++compno) + { + if (! j2k_write_coc_v2(p_j2k,compno,p_stream, p_manager)) { + return OPJ_FALSE; + } - /* first marker */ - opj_read_bytes(p_header_data,&l_tmp,2); /* Zmcc */ - p_header_data += 2; - if (l_tmp != 0) { - opj_event_msg_v2(p_manager, EVT_WARNING, "Cannot take in charge multiple data spanning\n"); - return OPJ_TRUE; + if (! j2k_write_qcc_v2(p_j2k,compno,p_stream, p_manager)) { + return OPJ_FALSE; + } } - if (p_header_size < 7) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCC marker\n"); - return OPJ_FALSE; - } + return OPJ_TRUE; +} - opj_read_bytes(p_header_data,&l_indix,1); /* Imcc -> no need for other values, take the first */ - ++p_header_data; +/** + * Writes regions of interests. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +opj_bool j2k_write_regions( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) +{ + OPJ_UINT32 compno; + const opj_tccp_t *l_tccp = 00; - l_mcc_record = l_tcp->m_mcc_records; + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); - for(i=0;im_nb_mcc_records;++i) { - if (l_mcc_record->m_index == l_indix) { - break; - } - ++l_mcc_record; - } + l_tccp = p_j2k->m_cp.tcps->tccps; - /** NOT FOUND */ - if (i == l_tcp->m_nb_mcc_records) { - if (l_tcp->m_nb_mcc_records == l_tcp->m_nb_max_mcc_records) { - l_tcp->m_nb_max_mcc_records += J2K_MCC_DEFAULT_NB_RECORDS; + for (compno = 0; compno < p_j2k->m_private_image->numcomps; ++compno) { + if (l_tccp->roishift) { - l_tcp->m_mcc_records = (opj_simple_mcc_decorrelation_data_t*) - opj_realloc(l_tcp->m_mcc_records,l_tcp->m_nb_max_mcc_records * sizeof(opj_simple_mcc_decorrelation_data_t)); - if (! l_tcp->m_mcc_records) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCC marker\n"); + if (! j2k_write_rgn_v2(p_j2k,0,compno,p_stream,p_manager)) { return OPJ_FALSE; } - l_mcc_record = l_tcp->m_mcc_records + l_tcp->m_nb_mcc_records; - memset(l_mcc_record,0,(l_tcp->m_nb_max_mcc_records-l_tcp->m_nb_mcc_records) * sizeof(opj_simple_mcc_decorrelation_data_t)); } - l_mcc_record = l_tcp->m_mcc_records + l_tcp->m_nb_mcc_records; - } - l_mcc_record->m_index = l_indix; - /* only one marker atm */ - opj_read_bytes(p_header_data,&l_tmp,2); /* Ymcc */ - p_header_data+=2; - if (l_tmp != 0) { - opj_event_msg_v2(p_manager, EVT_WARNING, "Cannot take in charge multiple data spanning\n"); - return OPJ_TRUE; + ++l_tccp; } - opj_read_bytes(p_header_data,&l_nb_collections,2); /* Qmcc -> number of collections -> 1 */ - p_header_data+=2; - - if (l_nb_collections > 1) { - opj_event_msg_v2(p_manager, EVT_WARNING, "Cannot take in charge multiple collections\n"); - return OPJ_TRUE; - } + return OPJ_TRUE; +} - p_header_size -= 7; +/** + * Writes EPC ???? + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +opj_bool j2k_write_epc( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) +{ + opj_codestream_index_t * l_cstr_index = 00; - for (i=0;i array based decorrelation */ - ++p_header_data; + l_cstr_index = p_j2k->cstr_index; + if (l_cstr_index) { + l_cstr_index->codestream_size = opj_stream_tell(p_stream); + /* UniPG>> */ + /* The following adjustment is done to adjust the codestream size */ + /* if SOD is not at 0 in the buffer. Useful in case of JP2, where */ + /* the first bunch of bytes is not in the codestream */ + l_cstr_index->codestream_size -= l_cstr_index->main_head_start; + /* <epc_on) { - opj_read_bytes(p_header_data,&l_nb_comps,2); + /* encode according to JPWL */ + jpwl_encode(p_j2k, p_stream, image); - p_header_data+=2; - p_header_size-=3; + } +#endif + assert( 0 && "TODO" ); +#endif /* USE_JPWL */ - l_nb_bytes_by_comp = 1 + (l_nb_comps>>15); - l_mcc_record->m_nb_comps = l_nb_comps & 0x7fff; + return OPJ_TRUE; +} - if (p_header_size < (l_nb_bytes_by_comp * l_mcc_record->m_nb_comps + 2)) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCC marker\n"); - return OPJ_FALSE; - } +typedef struct opj_dec_mstabent { + /** marker value */ + int id; + /** value of the state when the marker can appear */ + int states; + /** action linked to the marker */ + void (*handler) (opj_j2k_t *j2k); +} opj_dec_mstabent_t; - p_header_size -= (l_nb_bytes_by_comp * l_mcc_record->m_nb_comps + 2); +opj_dec_mstabent_t j2k_dec_mstab[] = { + {J2K_MS_SOC, J2K_STATE_MHSOC, j2k_read_soc}, + {J2K_MS_SOT, J2K_STATE_MH | J2K_STATE_TPHSOT, j2k_read_sot}, + {J2K_MS_SOD, J2K_STATE_TPH, j2k_read_sod}, + {J2K_MS_EOC, J2K_STATE_TPHSOT, j2k_read_eoc}, + {J2K_MS_SIZ, J2K_STATE_MHSIZ, j2k_read_siz}, + {J2K_MS_COD, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_cod}, + {J2K_MS_COC, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_coc}, + {J2K_MS_RGN, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_rgn}, + {J2K_MS_QCD, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_qcd}, + {J2K_MS_QCC, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_qcc}, + {J2K_MS_POC, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_poc}, + {J2K_MS_TLM, J2K_STATE_MH, j2k_read_tlm}, + {J2K_MS_PLM, J2K_STATE_MH, j2k_read_plm}, + {J2K_MS_PLT, J2K_STATE_TPH, j2k_read_plt}, + {J2K_MS_PPM, J2K_STATE_MH, j2k_read_ppm}, + {J2K_MS_PPT, J2K_STATE_TPH, j2k_read_ppt}, + {J2K_MS_SOP, 0, 0}, + {J2K_MS_CRG, J2K_STATE_MH, j2k_read_crg}, + {J2K_MS_COM, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_com}, - for (j=0;jm_nb_comps;++j) { - opj_read_bytes(p_header_data,&l_tmp,l_nb_bytes_by_comp); /* Cmccij Component offset*/ - p_header_data+=l_nb_bytes_by_comp; +#ifdef USE_JPWL + {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}, + {J2K_MS_RED, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_red}, +#endif /* USE_JPWL */ +#ifdef USE_JPSEC + {J2K_MS_SEC, J2K_STATE_MH, j2k_read_sec}, + {J2K_MS_INSEC, 0, j2k_read_insec}, +#endif /* USE_JPSEC */ - if (l_tmp != j) { - opj_event_msg_v2(p_manager, EVT_WARNING, "Cannot take in charge collections with indix shuffle\n"); - return OPJ_TRUE; + {0, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_unk} +}; + +static void j2k_read_unk(opj_j2k_t *j2k) { + opj_event_msg(j2k->cinfo, EVT_WARNING, "Unknown marker\n"); + +#ifdef USE_JPWL + if (j2k->cp->correct) { + int m = 0, id, i; + int min_id = 0, min_dist = 17, cur_dist = 0, tmp_id; + cio_seek(j2k->cio, cio_tell(j2k->cio) - 2); + id = cio_read(j2k->cio, 2); + opj_event_msg(j2k->cinfo, EVT_ERROR, + "JPWL: really don't know this marker %x\n", + id); + if (!JPWL_ASSUME) { + opj_event_msg(j2k->cinfo, EVT_ERROR, + "- possible synch loss due to uncorrectable codestream errors => giving up\n"); + return; + } + /* OK, activate this at your own risk!!! */ + /* we look for the marker at the minimum hamming distance from this */ + while (j2k_dec_mstab[m].id) { + + /* 1's where they differ */ + tmp_id = j2k_dec_mstab[m].id ^ id; + + /* compute the hamming distance between our id and the current */ + cur_dist = 0; + for (i = 0; i < 16; i++) { + if ((tmp_id >> i) & 0x0001) { + cur_dist++; + } + } + + /* if current distance is smaller, set the minimum */ + if (cur_dist < min_dist) { + min_dist = cur_dist; + min_id = j2k_dec_mstab[m].id; } + + /* jump to the next marker */ + m++; } - opj_read_bytes(p_header_data,&l_nb_comps,2); - p_header_data+=2; + /* do we substitute the marker? */ + if (min_dist < JPWL_MAXIMUM_HAMMING) { + opj_event_msg(j2k->cinfo, EVT_ERROR, + "- marker %x is at distance %d from the read %x\n", + min_id, min_dist, id); + opj_event_msg(j2k->cinfo, EVT_ERROR, + "- trying to substitute in place and crossing fingers!\n"); + cio_seek(j2k->cio, cio_tell(j2k->cio) - 2); + cio_write(j2k->cio, min_id, 2); - l_nb_bytes_by_comp = 1 + (l_nb_comps>>15); - l_nb_comps &= 0x7fff; + /* rewind */ + cio_seek(j2k->cio, cio_tell(j2k->cio) - 2); - if (l_nb_comps != l_mcc_record->m_nb_comps) { - opj_event_msg_v2(p_manager, EVT_WARNING, "Cannot take in charge collections without same number of indixes\n"); - return OPJ_TRUE; } - if (p_header_size < (l_nb_bytes_by_comp * l_mcc_record->m_nb_comps + 3)) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCC marker\n"); - return OPJ_FALSE; - } + }; +#endif /* USE_JPWL */ - p_header_size -= (l_nb_bytes_by_comp * l_mcc_record->m_nb_comps + 3); +} - for (j=0;jm_nb_comps;++j) { - opj_read_bytes(p_header_data,&l_tmp,l_nb_bytes_by_comp); /* Wmccij Component offset*/ - p_header_data+=l_nb_bytes_by_comp; +/** + * Reads an unknown marker + * + * @param p_stream the stream object to read from. + * @param p_j2k the jpeg2000 codec. + * @param p_manager the user event manager. + * + * @return true if the marker could be deduced. +*/ +opj_bool j2k_read_unk_v2 ( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + OPJ_UINT32 *output_marker, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 l_unknown_marker; + const opj_dec_memory_marker_handler_t * l_marker_handler; + OPJ_UINT32 l_size_unk = 2; - if (l_tmp != j) { - opj_event_msg_v2(p_manager, EVT_WARNING, "Cannot take in charge collections with indix shuffle\n"); - return OPJ_TRUE; - } + /* preconditions*/ + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + opj_event_msg_v2(p_manager, EVT_WARNING, "Unknown marker\n"); + + while(1) { + /* 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_v2(p_manager, EVT_ERROR, "Stream too short\n"); + return OPJ_FALSE; } - opj_read_bytes(p_header_data,&l_tmp,3); /* Wmccij Component offset*/ - p_header_data += 3; + /* read 2 bytes as the new marker ID*/ + opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data,&l_unknown_marker,2); - l_mcc_record->m_is_irreversible = ! ((l_tmp>>16) & 1); - l_mcc_record->m_decorrelation_array = 00; - l_mcc_record->m_offset_array = 00; + if (!(l_unknown_marker < 0xff00)) { - l_indix = l_tmp & 0xff; - if (l_indix != 0) { - l_mct_data = l_tcp->m_mct_records; - for (j=0;jm_nb_mct_records;++j) { - if (l_mct_data->m_index == l_indix) { - l_mcc_record->m_decorrelation_array = l_mct_data; - break; - } - ++l_mct_data; - } + /* Get the marker handler from the marker ID*/ + l_marker_handler = j2k_get_marker_handler(l_unknown_marker); - if (l_mcc_record->m_decorrelation_array == 00) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCC marker\n"); + if (!(p_j2k->m_specific_param.m_decoder.m_state & l_marker_handler->states)) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Marker is not compliant with its position\n"); return OPJ_FALSE; } - } - - l_indix = (l_tmp >> 8) & 0xff; - if (l_indix != 0) { - l_mct_data = l_tcp->m_mct_records; - for (j=0;jm_nb_mct_records;++j) { - if (l_mct_data->m_index == l_indix) { - l_mcc_record->m_offset_array = l_mct_data; - break; + else { + if (l_marker_handler->id != J2K_MS_UNK) { + /* Add the marker to the codestream index*/ + if (l_marker_handler->id != J2K_MS_SOT) + j2k_add_mhmarker_v2(p_j2k->cstr_index, J2K_MS_UNK, + (OPJ_UINT32) opj_stream_tell(p_stream) - l_size_unk, + l_size_unk); + break; /* next marker is known and well located */ } - ++l_mct_data; - } - - if (l_mcc_record->m_offset_array == 00) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCC marker\n"); - return OPJ_FALSE; + else + l_size_unk += 2; } } } - if (p_header_size != 0) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCC marker\n"); - return OPJ_FALSE; - } - - ++l_tcp->m_nb_mcc_records; + *output_marker = l_marker_handler->id ; return OPJ_TRUE; } /** - * Reads a MCO marker (Multiple Component Transform Ordering) +Read the lookup table containing all the marker, status and action +@param id Marker value +*/ +static opj_dec_mstabent_t *j2k_dec_mstab_lookup(int id) { + opj_dec_mstabent_t *e; + for (e = j2k_dec_mstab; e->id != 0; e++) { + if (e->id == id) { + break; + } + } + return e; +} + +/** + * Writes the MCT marker (Multiple Component Transform) * - * @param p_header_data the data contained in the MCO box. - * @param p_j2k the jpeg2000 codec. - * @param p_header_size the size of the data contained in the MCO marker. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. * @param p_manager the user event manager. */ -opj_bool j2k_read_mco ( opj_j2k_v2_t *p_j2k, - OPJ_BYTE * p_header_data, - OPJ_UINT32 p_header_size, - struct opj_event_mgr * p_manager ) +opj_bool j2k_write_mct_record( opj_j2k_v2_t *p_j2k, + opj_mct_data_t * p_mct_record, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) { - OPJ_UINT32 l_tmp, i; - OPJ_UINT32 l_nb_stages; - opj_tcp_v2_t * l_tcp; - opj_tccp_t * l_tccp; - opj_image_t * l_image; - opj_image_comp_t * l_img_comp; + OPJ_UINT32 l_mct_size; + OPJ_BYTE * l_current_data = 00; + OPJ_UINT32 l_tmp; /* preconditions */ - assert(p_header_data != 00); assert(p_j2k != 00); assert(p_manager != 00); + assert(p_stream != 00); - l_image = p_j2k->m_private_image; - l_tcp = p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_TPH ? - &p_j2k->m_cp.tcps[p_j2k->m_current_tile_number] : - p_j2k->m_specific_param.m_decoder.m_default_tcp; + l_mct_size = 10 + p_mct_record->m_data_size; - if (p_header_size < 1) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCO marker\n"); - return OPJ_FALSE; - } + if (l_mct_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = (OPJ_BYTE*)opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_mct_size); - opj_read_bytes(p_header_data,&l_nb_stages,1); /* Nmco : only one tranform stage*/ - ++p_header_data; + if (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) { + return OPJ_FALSE; + } - if (l_nb_stages > 1) { - opj_event_msg_v2(p_manager, EVT_WARNING, "Cannot take in charge multiple transformation stages.\n"); - return OPJ_TRUE; + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_mct_size; } - if (p_header_size != l_nb_stages + 1) { - opj_event_msg_v2(p_manager, EVT_WARNING, "Error reading MCO marker\n"); - return OPJ_FALSE; - } + l_current_data = p_j2k->m_specific_param.m_encoder.m_header_tile_data; - l_tccp = l_tcp->tccps; - l_img_comp = l_image->comps; + opj_write_bytes(l_current_data,J2K_MS_MCT,2); /* MCT */ + l_current_data += 2; - for (i=0;inumcomps;++i) { - l_tccp->m_dc_level_shift = 0; - ++l_tccp; - } + opj_write_bytes(l_current_data,l_mct_size-2,2); /* Lmct */ + l_current_data += 2; - if (l_tcp->m_mct_decoding_matrix) { - opj_free(l_tcp->m_mct_decoding_matrix); - l_tcp->m_mct_decoding_matrix = 00; - } + opj_write_bytes(l_current_data,0,2); /* Zmct */ + l_current_data += 2; - for (i=0;im_index & 0xff) | (p_mct_record->m_array_type << 8) | (p_mct_record->m_element_type << 10); - if (! j2k_add_mct(l_tcp,p_j2k->m_private_image,l_tmp)) { - return OPJ_FALSE; - } + opj_write_bytes(l_current_data,l_tmp,2); + l_current_data += 2; + + opj_write_bytes(l_current_data,0,2); /* Ymct */ + l_current_data+=2; + + memcpy(l_current_data,p_mct_record->m_data,p_mct_record->m_data_size); + + if (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_mct_size,p_manager) != l_mct_size) { + return OPJ_FALSE; } return OPJ_TRUE; } -opj_bool j2k_add_mct(opj_tcp_v2_t * p_tcp, opj_image_t * p_image, OPJ_UINT32 p_index) +/** + * Reads a MCT marker (Multiple Component Transform) + * + * @param p_header_data the data contained in the MCT box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the MCT marker. + * @param p_manager the user event manager. +*/ +opj_bool j2k_read_mct ( opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager ) { OPJ_UINT32 i; - opj_simple_mcc_decorrelation_data_t * l_mcc_record; - opj_mct_data_t * l_deco_array, * l_offset_array; - OPJ_UINT32 l_data_size,l_mct_size, l_offset_size; - OPJ_UINT32 l_nb_elem; - OPJ_UINT32 * l_offset_data, * l_current_offset_data; - opj_tccp_t * l_tccp; + opj_tcp_v2_t *l_tcp = 00; + OPJ_UINT32 l_tmp; + OPJ_UINT32 l_indix; + opj_mct_data_t * l_mct_data; /* preconditions */ - assert(p_tcp != 00); + assert(p_header_data != 00); + assert(p_j2k != 00); - l_mcc_record = p_tcp->m_mcc_records; + l_tcp = p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_TPH ? + &p_j2k->m_cp.tcps[p_j2k->m_current_tile_number] : + p_j2k->m_specific_param.m_decoder.m_default_tcp; - for (i=0;im_nb_mcc_records;++i) { - if (l_mcc_record->m_index == p_index) { - break; - } + if (p_header_size < 2) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCT marker\n"); + return OPJ_FALSE; } - if (i==p_tcp->m_nb_mcc_records) { - /** element discarded **/ + /* first marker */ + opj_read_bytes(p_header_data,&l_tmp,2); /* Zmct */ + p_header_data += 2; + if (l_tmp != 0) { + opj_event_msg_v2(p_manager, EVT_WARNING, "Cannot take in charge mct data within multiple MCT records\n"); return OPJ_TRUE; } - if (l_mcc_record->m_nb_comps != p_image->numcomps) { - /** do not support number of comps != image */ - return OPJ_TRUE; + if(p_header_size <= 6) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCT marker\n"); + return OPJ_FALSE; } - l_deco_array = l_mcc_record->m_decorrelation_array; - - if (l_deco_array) { - l_data_size = MCT_ELEMENT_SIZE[l_deco_array->m_element_type] * p_image->numcomps * p_image->numcomps; - if (l_deco_array->m_data_size != l_data_size) { - return OPJ_FALSE; - } + /* Imct -> no need for other values, take the first, type is double with decorrelation x0000 1101 0000 0000*/ + opj_read_bytes(p_header_data,&l_tmp,2); /* Imct */ + p_header_data += 2; - l_nb_elem = p_image->numcomps * p_image->numcomps; - l_mct_size = l_nb_elem * sizeof(OPJ_FLOAT32); - p_tcp->m_mct_decoding_matrix = (OPJ_FLOAT32*)opj_malloc(l_mct_size); + l_indix = l_tmp & 0xff; + l_mct_data = l_tcp->m_mct_records; - if (! p_tcp->m_mct_decoding_matrix ) { - return OPJ_FALSE; + for (i=0;im_nb_mct_records;++i) { + if (l_mct_data->m_index == l_indix) { + break; } - - j2k_mct_read_functions_to_float[l_deco_array->m_element_type](l_deco_array->m_data,p_tcp->m_mct_decoding_matrix,l_nb_elem); + ++l_mct_data; } - l_offset_array = l_mcc_record->m_offset_array; + /* NOT FOUND */ + if (i == l_tcp->m_nb_mct_records) { + if (l_tcp->m_nb_mct_records == l_tcp->m_nb_max_mct_records) { + l_tcp->m_nb_max_mct_records += J2K_MCT_DEFAULT_NB_RECORDS; - if (l_offset_array) { - l_data_size = MCT_ELEMENT_SIZE[l_offset_array->m_element_type] * p_image->numcomps; - if (l_offset_array->m_data_size != l_data_size) { - return OPJ_FALSE; + l_tcp->m_mct_records = (opj_mct_data_t*)opj_realloc(l_tcp->m_mct_records,l_tcp->m_nb_max_mct_records * sizeof(opj_mct_data_t)); + if(! l_tcp->m_mct_records) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCT marker\n"); + return OPJ_FALSE; + } + + l_mct_data = l_tcp->m_mct_records + l_tcp->m_nb_mct_records; + memset(l_mct_data ,0,(l_tcp->m_nb_max_mct_records - l_tcp->m_nb_mct_records) * sizeof(opj_mct_data_t)); } - l_nb_elem = p_image->numcomps; - l_offset_size = l_nb_elem * sizeof(OPJ_UINT32); - l_offset_data = (OPJ_UINT32*)opj_malloc(l_offset_size); + l_mct_data = l_tcp->m_mct_records + l_tcp->m_nb_mct_records; + } - if (! l_offset_data ) { - return OPJ_FALSE; - } + if (l_mct_data->m_data) { + opj_free(l_mct_data->m_data); + l_mct_data->m_data = 00; + } - j2k_mct_read_functions_to_int32[l_offset_array->m_element_type](l_offset_array->m_data,l_offset_data,l_nb_elem); + l_mct_data->m_index = l_indix; + l_mct_data->m_array_type = (J2K_MCT_ARRAY_TYPE)((l_tmp >> 8) & 3); + l_mct_data->m_element_type = (J2K_MCT_ELEMENT_TYPE)((l_tmp >> 10) & 3); - l_tccp = p_tcp->tccps; - l_current_offset_data = l_offset_data; + opj_read_bytes(p_header_data,&l_tmp,2); /* Ymct */ + p_header_data+=2; + if (l_tmp != 0) { + opj_event_msg_v2(p_manager, EVT_WARNING, "Cannot take in charge multiple MCT markers\n"); + return OPJ_TRUE; + } - for (i=0;inumcomps;++i) { - l_tccp->m_dc_level_shift = *(l_current_offset_data++); - ++l_tccp; - } + p_header_size -= 6; - opj_free(l_offset_data); + l_mct_data->m_data = (OPJ_BYTE*)opj_malloc(p_header_size); + if (! l_mct_data->m_data) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCT marker\n"); + return OPJ_FALSE; } + memcpy(l_mct_data->m_data,p_header_data,p_header_size); + + l_mct_data->m_data_size = p_header_size; + ++l_tcp->m_nb_mct_records; return OPJ_TRUE; } /** - * Reads a CBD marker (Component bit depth definition) - * @param p_header_data the data contained in the CBD box. - * @param p_j2k the jpeg2000 codec. - * @param p_header_size the size of the data contained in the CBD marker. + * Writes the MCC marker (Multiple Component Collection) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. * @param p_manager the user event manager. */ -opj_bool j2k_read_cbd ( opj_j2k_v2_t *p_j2k, - OPJ_BYTE * p_header_data, - OPJ_UINT32 p_header_size, - struct opj_event_mgr * p_manager) +opj_bool j2k_write_mcc_record( opj_j2k_v2_t *p_j2k, + struct opj_simple_mcc_decorrelation_data * p_mcc_record, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) { - OPJ_UINT32 l_nb_comp,l_num_comp; - OPJ_UINT32 l_comp_def; OPJ_UINT32 i; - opj_image_comp_t * l_comp = 00; + OPJ_UINT32 l_mcc_size; + OPJ_BYTE * l_current_data = 00; + OPJ_UINT32 l_nb_bytes_for_comp; + OPJ_UINT32 l_mask; + OPJ_UINT32 l_tmcc; /* preconditions */ - assert(p_header_data != 00); assert(p_j2k != 00); assert(p_manager != 00); + assert(p_stream != 00); - l_num_comp = p_j2k->m_private_image->numcomps; - - if (p_header_size != (p_j2k->m_private_image->numcomps + 2)) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Crror reading CBD marker\n"); - return OPJ_FALSE; + if (p_mcc_record->m_nb_comps > 255 ) { + l_nb_bytes_for_comp = 2; + l_mask = 0x8000; + } + else { + l_nb_bytes_for_comp = 1; + l_mask = 0; } - opj_read_bytes(p_header_data,&l_nb_comp,2); /* Ncbd */ - p_header_data+=2; + l_mcc_size = p_mcc_record->m_nb_comps * 2 * l_nb_bytes_for_comp + 19; + if (l_mcc_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) + { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = (OPJ_BYTE*)opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_mcc_size); + if (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) { + return OPJ_FALSE; + } - if (l_nb_comp != l_num_comp) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Crror reading CBD marker\n"); - return OPJ_FALSE; + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_mcc_size; } - l_comp = p_j2k->m_private_image->comps; - for (i=0;isgnd = (l_comp_def>>7) & 1; - l_comp->prec = (l_comp_def&0x7f) + 1; - ++l_comp; - } + l_current_data = p_j2k->m_specific_param.m_encoder.m_header_tile_data; - return OPJ_TRUE; -} + opj_write_bytes(l_current_data,J2K_MS_MCC,2); /* MCC */ + l_current_data += 2; + opj_write_bytes(l_current_data,l_mcc_size-2,2); /* Lmcc */ + l_current_data += 2; -/* ----------------------------------------------------------------------- */ -/* J2K / JPT decoder interface */ -/* ----------------------------------------------------------------------- */ + /* first marker */ + opj_write_bytes(l_current_data,0,2); /* Zmcc */ + l_current_data += 2; -opj_j2k_t* j2k_create_decompress(opj_common_ptr cinfo) { - opj_j2k_t *j2k = (opj_j2k_t*) opj_calloc(1, sizeof(opj_j2k_t)); - if(!j2k) - return NULL; + opj_write_bytes(l_current_data,p_mcc_record->m_index,1); /* Imcc -> no need for other values, take the first */ + ++l_current_data; - j2k->default_tcp = (opj_tcp_t*) opj_calloc(1, sizeof(opj_tcp_t)); - if(!j2k->default_tcp) { - opj_free(j2k); - return NULL; - } + /* only one marker atm */ + opj_write_bytes(l_current_data,0,2); /* Ymcc */ + l_current_data+=2; - j2k->cinfo = cinfo; - j2k->tile_data = NULL; + opj_write_bytes(l_current_data,1,2); /* Qmcc -> number of collections -> 1 */ + l_current_data+=2; - return j2k; -} + opj_write_bytes(l_current_data,0x1,1); /* Xmcci type of component transformation -> array based decorrelation */ + ++l_current_data; -void j2k_destroy_decompress(opj_j2k_t *j2k) { - int i = 0; + opj_write_bytes(l_current_data,p_mcc_record->m_nb_comps | l_mask,2); /* Nmcci number of input components involved and size for each component offset = 8 bits */ + l_current_data+=2; - if(j2k->tile_len != NULL) { - opj_free(j2k->tile_len); - } - if(j2k->tile_data != NULL) { - opj_free(j2k->tile_data); - } - if(j2k->default_tcp != NULL) { - opj_tcp_t *default_tcp = j2k->default_tcp; - if(default_tcp->ppt_data_first != NULL) { - opj_free(default_tcp->ppt_data_first); - } - if(j2k->default_tcp->tccps != NULL) { - opj_free(j2k->default_tcp->tccps); - } - opj_free(j2k->default_tcp); + for (i=0;im_nb_comps;++i) { + opj_write_bytes(l_current_data,i,l_nb_bytes_for_comp); /* Cmccij Component offset*/ + l_current_data+=l_nb_bytes_for_comp; } - if(j2k->cp != NULL) { - opj_cp_t *cp = j2k->cp; - if(cp->tcps != NULL) { - for(i = 0; i < cp->tw * cp->th; i++) { - if(cp->tcps[i].ppt_data_first != NULL) { - opj_free(cp->tcps[i].ppt_data_first); - } - if(cp->tcps[i].tccps != NULL) { - opj_free(cp->tcps[i].tccps); - } - } - opj_free(cp->tcps); - } - if(cp->ppm_data_first != NULL) { - opj_free(cp->ppm_data_first); - } - if(cp->tileno != NULL) { - opj_free(cp->tileno); - } - if(cp->comment != NULL) { - opj_free(cp->comment); - } - opj_free(cp); - } - opj_free(j2k); -} + opj_write_bytes(l_current_data,p_mcc_record->m_nb_comps|l_mask,2); /* Mmcci number of output components involved and size for each component offset = 8 bits */ + l_current_data+=2; -void j2k_setup_decoder(opj_j2k_t *j2k, opj_dparameters_t *parameters) { - if(j2k && parameters) { - /* create and initialize the coding parameters structure */ - opj_cp_t *cp = (opj_cp_t*) opj_calloc(1, sizeof(opj_cp_t)); - cp->reduce = parameters->cp_reduce; - cp->layer = parameters->cp_layer; - cp->limit_decoding = parameters->cp_limit_decoding; + for (i=0;im_nb_comps;++i) + { + opj_write_bytes(l_current_data,i,l_nb_bytes_for_comp); /* Wmccij Component offset*/ + l_current_data+=l_nb_bytes_for_comp; + } -#ifdef USE_JPWL - cp->correct = parameters->jpwl_correct; - cp->exp_comps = parameters->jpwl_exp_comps; - cp->max_tiles = parameters->jpwl_max_tiles; -#endif /* USE_JPWL */ + l_tmcc = ((!p_mcc_record->m_is_irreversible)&1)<<16; + if (p_mcc_record->m_decorrelation_array) { + l_tmcc |= p_mcc_record->m_decorrelation_array->m_index; + } - /* keep a link to cp so that we can destroy it later in j2k_destroy_decompress */ - j2k->cp = cp; + if (p_mcc_record->m_offset_array) { + l_tmcc |= ((p_mcc_record->m_offset_array->m_index)<<8); } -} -void j2k_setup_decoder_v2(opj_j2k_v2_t *j2k, opj_dparameters_t *parameters) -{ - if(j2k && parameters) { - j2k->m_cp.m_specific_param.m_dec.m_layer = parameters->cp_layer; - j2k->m_cp.m_specific_param.m_dec.m_reduce = parameters->cp_reduce; + opj_write_bytes(l_current_data,l_tmcc,3); /* Tmcci : use MCT defined as number 1 and irreversible array based. */ + l_current_data+=3; -#ifdef USE_JPWL - j2k->m_cp.correct = parameters->jpwl_correct; - j2k->m_cp.exp_comps = parameters->jpwl_exp_comps; - j2k->m_cp.max_tiles = parameters->jpwl_max_tiles; -#endif /* USE_JPWL */ + if (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_mcc_size,p_manager) != l_mcc_size) { + return OPJ_FALSE; } + + return OPJ_TRUE; } -opj_image_t* j2k_decode(opj_j2k_t *j2k, opj_cio_t *cio, opj_codestream_info_t *cstr_info) { - opj_image_t *image = NULL; +/** + * Reads a MCC marker (Multiple Component Collection) + * + * @param p_header_data the data contained in the MCC box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the MCC marker. + * @param p_manager the user event manager. +*/ +opj_bool j2k_read_mcc ( opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager ) +{ + OPJ_UINT32 i,j; + OPJ_UINT32 l_tmp; + OPJ_UINT32 l_indix; + opj_tcp_v2_t * l_tcp; + opj_simple_mcc_decorrelation_data_t * l_mcc_record; + opj_mct_data_t * l_mct_data; + OPJ_UINT32 l_nb_collections; + OPJ_UINT32 l_nb_comps; + OPJ_UINT32 l_nb_bytes_by_comp; - opj_common_ptr cinfo = j2k->cinfo; - j2k->cio = cio; - j2k->cstr_info = cstr_info; - if (cstr_info) - memset(cstr_info, 0, sizeof(opj_codestream_info_t)); + /* preconditions */ + assert(p_header_data != 00); + assert(p_j2k != 00); + assert(p_manager != 00); - /* create an empty image */ - image = opj_image_create0(); - j2k->image = image; + l_tcp = p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_TPH ? + &p_j2k->m_cp.tcps[p_j2k->m_current_tile_number] : + p_j2k->m_specific_param.m_decoder.m_default_tcp; - j2k->state = J2K_STATE_MHSOC; + if (p_header_size < 2) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCC marker\n"); + return OPJ_FALSE; + } - for (;;) { - opj_dec_mstabent_t *e; - int id = cio_read(cio, 2); + /* first marker */ + opj_read_bytes(p_header_data,&l_tmp,2); /* Zmcc */ + p_header_data += 2; + if (l_tmp != 0) { + opj_event_msg_v2(p_manager, EVT_WARNING, "Cannot take in charge multiple data spanning\n"); + return OPJ_TRUE; + } -#ifdef USE_JPWL - /* we try to honor JPWL correction power */ - if (j2k->cp->correct) { + if (p_header_size < 7) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCC marker\n"); + return OPJ_FALSE; + } - int orig_pos = cio_tell(cio); - opj_bool status; + opj_read_bytes(p_header_data,&l_indix,1); /* Imcc -> no need for other values, take the first */ + ++p_header_data; - /* call the corrector */ - status = jpwl_correct(j2k); + l_mcc_record = l_tcp->m_mcc_records; - /* go back to where you were */ - cio_seek(cio, orig_pos - 2); + for(i=0;im_nb_mcc_records;++i) { + if (l_mcc_record->m_index == l_indix) { + break; + } + ++l_mcc_record; + } - /* re-read the marker */ - id = cio_read(cio, 2); + /** NOT FOUND */ + if (i == l_tcp->m_nb_mcc_records) { + if (l_tcp->m_nb_mcc_records == l_tcp->m_nb_max_mcc_records) { + l_tcp->m_nb_max_mcc_records += J2K_MCC_DEFAULT_NB_RECORDS; - /* check whether it begins with ff */ - if (id >> 8 != 0xff) { - opj_event_msg(cinfo, EVT_ERROR, - "JPWL: possible bad marker %x at %d\n", - id, cio_tell(cio) - 2); - if (!JPWL_ASSUME) { - opj_image_destroy(image); - opj_event_msg(cinfo, EVT_ERROR, "JPWL: giving up\n"); - return 0; - } - /* we try to correct */ - id = id | 0xff00; - cio_seek(cio, cio_tell(cio) - 2); - cio_write(cio, id, 2); - opj_event_msg(cinfo, EVT_WARNING, "- trying to adjust this\n" - "- setting marker to %x\n", - id); + l_tcp->m_mcc_records = (opj_simple_mcc_decorrelation_data_t*) + opj_realloc(l_tcp->m_mcc_records,l_tcp->m_nb_max_mcc_records * sizeof(opj_simple_mcc_decorrelation_data_t)); + if (! l_tcp->m_mcc_records) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCC marker\n"); + return OPJ_FALSE; } + l_mcc_record = l_tcp->m_mcc_records + l_tcp->m_nb_mcc_records; + memset(l_mcc_record,0,(l_tcp->m_nb_max_mcc_records-l_tcp->m_nb_mcc_records) * sizeof(opj_simple_mcc_decorrelation_data_t)); + } + l_mcc_record = l_tcp->m_mcc_records + l_tcp->m_nb_mcc_records; + } + l_mcc_record->m_index = l_indix; + + /* only one marker atm */ + opj_read_bytes(p_header_data,&l_tmp,2); /* Ymcc */ + p_header_data+=2; + if (l_tmp != 0) { + opj_event_msg_v2(p_manager, EVT_WARNING, "Cannot take in charge multiple data spanning\n"); + return OPJ_TRUE; + } + + opj_read_bytes(p_header_data,&l_nb_collections,2); /* Qmcc -> number of collections -> 1 */ + p_header_data+=2; + + if (l_nb_collections > 1) { + opj_event_msg_v2(p_manager, EVT_WARNING, "Cannot take in charge multiple collections\n"); + return OPJ_TRUE; + } + + p_header_size -= 7; + for (i=0;i> 8 != 0xff) { - opj_image_destroy(image); - opj_event_msg(cinfo, EVT_ERROR, "%.8x: expected a marker instead of %x\n", cio_tell(cio) - 2, id); - return 0; + opj_read_bytes(p_header_data,&l_tmp,1); /* Xmcci type of component transformation -> array based decorrelation */ + ++p_header_data; + + if (l_tmp != 1) { + opj_event_msg_v2(p_manager, EVT_WARNING, "Cannot take in charge collections other than array decorrelation\n"); + return OPJ_TRUE; } - e = j2k_dec_mstab_lookup(id); - // Check if the marker is known - if (!(j2k->state & e->states)) { - opj_image_destroy(image); - opj_event_msg(cinfo, EVT_ERROR, "%.8x: unexpected marker %x\n", cio_tell(cio) - 2, id); - return 0; + + opj_read_bytes(p_header_data,&l_nb_comps,2); + + p_header_data+=2; + p_header_size-=3; + + l_nb_bytes_by_comp = 1 + (l_nb_comps>>15); + l_mcc_record->m_nb_comps = l_nb_comps & 0x7fff; + + if (p_header_size < (l_nb_bytes_by_comp * l_mcc_record->m_nb_comps + 2)) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCC marker\n"); + return OPJ_FALSE; } - // Check if the decoding is limited to the main header - if (e->id == J2K_MS_SOT && j2k->cp->limit_decoding == LIMIT_TO_MAIN_HEADER) { - opj_event_msg(cinfo, EVT_INFO, "Main Header decoded.\n"); - return image; - } - if (e->handler) { - (*e->handler)(j2k); + p_header_size -= (l_nb_bytes_by_comp * l_mcc_record->m_nb_comps + 2); + + for (j=0;jm_nb_comps;++j) { + opj_read_bytes(p_header_data,&l_tmp,l_nb_bytes_by_comp); /* Cmccij Component offset*/ + p_header_data+=l_nb_bytes_by_comp; + + if (l_tmp != j) { + opj_event_msg_v2(p_manager, EVT_WARNING, "Cannot take in charge collections with indix shuffle\n"); + return OPJ_TRUE; + } } - if (j2k->state & J2K_STATE_ERR) - return NULL; - if (j2k->state == J2K_STATE_MT) { - break; + opj_read_bytes(p_header_data,&l_nb_comps,2); + p_header_data+=2; + + l_nb_bytes_by_comp = 1 + (l_nb_comps>>15); + l_nb_comps &= 0x7fff; + + if (l_nb_comps != l_mcc_record->m_nb_comps) { + opj_event_msg_v2(p_manager, EVT_WARNING, "Cannot take in charge collections without same number of indixes\n"); + return OPJ_TRUE; } - if (j2k->state == J2K_STATE_NEOC) { - break; + + if (p_header_size < (l_nb_bytes_by_comp * l_mcc_record->m_nb_comps + 3)) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCC marker\n"); + return OPJ_FALSE; } - } - if (j2k->state == J2K_STATE_NEOC) { - j2k_read_eoc(j2k); - } - if (j2k->state != J2K_STATE_MT) { - opj_event_msg(cinfo, EVT_WARNING, "Incomplete bitstream\n"); - } - return image; -} + p_header_size -= (l_nb_bytes_by_comp * l_mcc_record->m_nb_comps + 3); -/* -* Read a JPT-stream and decode file -* -*/ -opj_image_t* j2k_decode_jpt_stream(opj_j2k_t *j2k, opj_cio_t *cio, opj_codestream_info_t *cstr_info) { - opj_image_t *image = NULL; - opj_jpt_msg_header_t header; - int position; - opj_common_ptr cinfo = j2k->cinfo; + for (j=0;jm_nb_comps;++j) { + opj_read_bytes(p_header_data,&l_tmp,l_nb_bytes_by_comp); /* Wmccij Component offset*/ + p_header_data+=l_nb_bytes_by_comp; - OPJ_ARG_NOT_USED(cstr_info); + if (l_tmp != j) { + opj_event_msg_v2(p_manager, EVT_WARNING, "Cannot take in charge collections with indix shuffle\n"); + return OPJ_TRUE; + } + } - j2k->cio = cio; + opj_read_bytes(p_header_data,&l_tmp,3); /* Wmccij Component offset*/ + p_header_data += 3; - /* create an empty image */ - image = opj_image_create0(); - j2k->image = image; + l_mcc_record->m_is_irreversible = ! ((l_tmp>>16) & 1); + l_mcc_record->m_decorrelation_array = 00; + l_mcc_record->m_offset_array = 00; - j2k->state = J2K_STATE_MHSOC; - - /* Initialize the header */ - jpt_init_msg_header(&header); - /* Read the first header of the message */ - jpt_read_msg_header(cinfo, cio, &header); - - position = cio_tell(cio); - if (header.Class_Id != 6) { /* 6 : Main header data-bin message */ - opj_image_destroy(image); - opj_event_msg(cinfo, EVT_ERROR, "[JPT-stream] : Expecting Main header first [class_Id %d] !\n", header.Class_Id); - return 0; - } - - for (;;) { - opj_dec_mstabent_t *e = NULL; - int id; - - if (!cio_numbytesleft(cio)) { - j2k_read_eoc(j2k); - return image; - } - /* data-bin read -> need to read a new header */ - if ((unsigned int) (cio_tell(cio) - position) == header.Msg_length) { - jpt_read_msg_header(cinfo, cio, &header); - position = cio_tell(cio); - if (header.Class_Id != 4) { /* 4 : Tile data-bin message */ - opj_image_destroy(image); - opj_event_msg(cinfo, EVT_ERROR, "[JPT-stream] : Expecting Tile info !\n"); - return 0; + l_indix = l_tmp & 0xff; + if (l_indix != 0) { + l_mct_data = l_tcp->m_mct_records; + for (j=0;jm_nb_mct_records;++j) { + if (l_mct_data->m_index == l_indix) { + l_mcc_record->m_decorrelation_array = l_mct_data; + break; + } + ++l_mct_data; + } + + if (l_mcc_record->m_decorrelation_array == 00) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCC marker\n"); + return OPJ_FALSE; } } - - id = cio_read(cio, 2); - if (id >> 8 != 0xff) { - opj_image_destroy(image); - opj_event_msg(cinfo, EVT_ERROR, "%.8x: expected a marker instead of %x\n", cio_tell(cio) - 2, id); - return 0; - } - e = j2k_dec_mstab_lookup(id); - if (!(j2k->state & e->states)) { - opj_image_destroy(image); - opj_event_msg(cinfo, EVT_ERROR, "%.8x: unexpected marker %x\n", cio_tell(cio) - 2, id); - return 0; - } - if (e->handler) { - (*e->handler)(j2k); - } - if (j2k->state == J2K_STATE_MT) { - break; - } - if (j2k->state == J2K_STATE_NEOC) { - break; + + l_indix = (l_tmp >> 8) & 0xff; + if (l_indix != 0) { + l_mct_data = l_tcp->m_mct_records; + for (j=0;jm_nb_mct_records;++j) { + if (l_mct_data->m_index == l_indix) { + l_mcc_record->m_offset_array = l_mct_data; + break; + } + ++l_mct_data; + } + + if (l_mcc_record->m_offset_array == 00) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCC marker\n"); + return OPJ_FALSE; + } } } - if (j2k->state == J2K_STATE_NEOC) { - j2k_read_eoc(j2k); - } - - if (j2k->state != J2K_STATE_MT) { - opj_event_msg(cinfo, EVT_WARNING, "Incomplete bitstream\n"); - } - return image; -} + if (p_header_size != 0) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCC marker\n"); + return OPJ_FALSE; + } -/* ----------------------------------------------------------------------- */ -/* J2K encoder interface */ -/* ----------------------------------------------------------------------- */ + ++l_tcp->m_nb_mcc_records; -opj_j2k_t* j2k_create_compress(opj_common_ptr cinfo) { - opj_j2k_t *j2k = (opj_j2k_t*) opj_calloc(1, sizeof(opj_j2k_t)); - if(j2k) { - j2k->cinfo = cinfo; - } - return j2k; + return OPJ_TRUE; } -opj_j2k_v2_t* j2k_create_compress_v2() + +/** + * Writes the MCO marker (Multiple component transformation ordering) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +opj_bool j2k_write_mco( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) { - opj_j2k_v2_t *l_j2k = (opj_j2k_v2_t*) opj_malloc(sizeof(opj_j2k_v2_t)); - if (!l_j2k) { - return NULL; - } + OPJ_BYTE * l_current_data = 00; + OPJ_UINT32 l_mco_size; + opj_tcp_v2_t * l_tcp = 00; + opj_simple_mcc_decorrelation_data_t * l_mcc_record; + OPJ_UINT32 i; - memset(l_j2k,0,sizeof(opj_j2k_v2_t)); + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); - l_j2k->m_is_decoder = 0; - l_j2k->m_cp.m_is_decoder = 0; + l_tcp =&(p_j2k->m_cp.tcps[p_j2k->m_current_tile_number]); + l_current_data = p_j2k->m_specific_param.m_encoder.m_header_tile_data; - l_j2k->m_specific_param.m_encoder.m_header_tile_data = (OPJ_BYTE *) opj_malloc(J2K_DEFAULT_HEADER_SIZE); - if (! l_j2k->m_specific_param.m_encoder.m_header_tile_data) { - j2k_destroy(l_j2k); - return NULL; - } + l_mco_size = 5 + l_tcp->m_nb_mcc_records; + if (l_mco_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) { - l_j2k->m_specific_param.m_encoder.m_header_tile_data_size = J2K_DEFAULT_HEADER_SIZE; + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = (OPJ_BYTE*)opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_mco_size); + if (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) + { + return OPJ_FALSE; + } - // validation list creation - l_j2k->m_validation_list = opj_procedure_list_create(); - if (! l_j2k->m_validation_list) { - j2k_destroy(l_j2k); - return NULL; + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_mco_size; } - // execution list creation - l_j2k->m_procedure_list = opj_procedure_list_create(); - if (! l_j2k->m_procedure_list) { - j2k_destroy(l_j2k); - return NULL; - } + opj_write_bytes(l_current_data,J2K_MS_MCO,2); /* MCO */ + l_current_data += 2; - return l_j2k; -} + opj_write_bytes(l_current_data,l_mco_size-2,2); /* Lmco */ + l_current_data += 2; -void j2k_destroy_compress(opj_j2k_t *j2k) { - int tileno; + opj_write_bytes(l_current_data,l_tcp->m_nb_mcc_records,1); /* Nmco : only one tranform stage*/ + ++l_current_data; - if(!j2k) return; - if(j2k->cp != NULL) { - opj_cp_t *cp = j2k->cp; + l_mcc_record = l_tcp->m_mcc_records; + for (i=0;im_nb_mcc_records;++i) { + opj_write_bytes(l_current_data,l_mcc_record->m_index,1); /* Imco -> use the mcc indicated by 1*/ + ++l_current_data; - if(cp->comment) { - opj_free(cp->comment); - } - if(cp->matrice) { - opj_free(cp->matrice); - } - for (tileno = 0; tileno < cp->tw * cp->th; tileno++) { - opj_free(cp->tcps[tileno].tccps); - } - opj_free(cp->tcps); - opj_free(cp); + ++l_mcc_record; } - opj_free(j2k); + if (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_mco_size,p_manager) != l_mco_size) { + return OPJ_FALSE; + } + + return OPJ_TRUE; } -void j2k_setup_encoder(opj_j2k_t *j2k, opj_cparameters_t *parameters, opj_image_t *image) { - int i, j, tileno, numpocs_tile; - opj_cp_t *cp = NULL; +/** + * Reads a MCO marker (Multiple Component Transform Ordering) + * + * @param p_header_data the data contained in the MCO box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the MCO marker. + * @param p_manager the user event manager. +*/ +opj_bool j2k_read_mco ( opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager ) +{ + OPJ_UINT32 l_tmp, i; + OPJ_UINT32 l_nb_stages; + opj_tcp_v2_t * l_tcp; + opj_tccp_t * l_tccp; + opj_image_t * l_image; + opj_image_comp_t * l_img_comp; - if(!j2k || !parameters || ! image) { - return; + /* preconditions */ + assert(p_header_data != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + l_image = p_j2k->m_private_image; + l_tcp = p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_TPH ? + &p_j2k->m_cp.tcps[p_j2k->m_current_tile_number] : + p_j2k->m_specific_param.m_decoder.m_default_tcp; + + if (p_header_size < 1) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCO marker\n"); + return OPJ_FALSE; } - /* create and initialize the coding parameters structure */ - cp = (opj_cp_t*) opj_calloc(1, sizeof(opj_cp_t)); + opj_read_bytes(p_header_data,&l_nb_stages,1); /* Nmco : only one tranform stage*/ + ++p_header_data; - /* keep a link to cp so that we can destroy it later in j2k_destroy_compress */ - j2k->cp = cp; + if (l_nb_stages > 1) { + opj_event_msg_v2(p_manager, EVT_WARNING, "Cannot take in charge multiple transformation stages.\n"); + return OPJ_TRUE; + } - /* set default values for cp */ - cp->tw = 1; - cp->th = 1; + if (p_header_size != l_nb_stages + 1) { + opj_event_msg_v2(p_manager, EVT_WARNING, "Error reading MCO marker\n"); + return OPJ_FALSE; + } - /* - copy user encoding parameters - */ - cp->cinema = parameters->cp_cinema; - cp->max_comp_size = parameters->max_comp_size; - cp->rsiz = parameters->cp_rsiz; - cp->disto_alloc = parameters->cp_disto_alloc; - cp->fixed_alloc = parameters->cp_fixed_alloc; - cp->fixed_quality = parameters->cp_fixed_quality; + l_tccp = l_tcp->tccps; + l_img_comp = l_image->comps; - /* mod fixed_quality */ - if(parameters->cp_matrice) { - size_t array_size = parameters->tcp_numlayers * parameters->numresolution * 3 * sizeof(int); - cp->matrice = (int *) opj_malloc(array_size); - memcpy(cp->matrice, parameters->cp_matrice, array_size); + for (i=0;inumcomps;++i) { + l_tccp->m_dc_level_shift = 0; + ++l_tccp; } - /* tiles */ - cp->tdx = parameters->cp_tdx; - cp->tdy = parameters->cp_tdy; + if (l_tcp->m_mct_decoding_matrix) { + opj_free(l_tcp->m_mct_decoding_matrix); + l_tcp->m_mct_decoding_matrix = 00; + } - /* tile offset */ - cp->tx0 = parameters->cp_tx0; - cp->ty0 = parameters->cp_ty0; + for (i=0;icp_comment) { - cp->comment = (char*)opj_malloc(strlen(parameters->cp_comment) + 1); - if(cp->comment) { - strcpy(cp->comment, parameters->cp_comment); + if (! j2k_add_mct(l_tcp,p_j2k->m_private_image,l_tmp)) { + return OPJ_FALSE; } } - /* - calculate other encoding parameters - */ + return OPJ_TRUE; +} - if (parameters->tile_size_on) { - cp->tw = int_ceildiv(image->x1 - cp->tx0, cp->tdx); - cp->th = int_ceildiv(image->y1 - cp->ty0, cp->tdy); - } else { - cp->tdx = image->x1 - cp->tx0; - cp->tdy = image->y1 - cp->ty0; - } +opj_bool j2k_add_mct(opj_tcp_v2_t * p_tcp, opj_image_t * p_image, OPJ_UINT32 p_index) +{ + OPJ_UINT32 i; + opj_simple_mcc_decorrelation_data_t * l_mcc_record; + opj_mct_data_t * l_deco_array, * l_offset_array; + OPJ_UINT32 l_data_size,l_mct_size, l_offset_size; + OPJ_UINT32 l_nb_elem; + OPJ_UINT32 * l_offset_data, * l_current_offset_data; + opj_tccp_t * l_tccp; - if(parameters->tp_on){ - cp->tp_flag = parameters->tp_flag; - cp->tp_on = 1; + /* preconditions */ + assert(p_tcp != 00); + + l_mcc_record = p_tcp->m_mcc_records; + + for (i=0;im_nb_mcc_records;++i) { + if (l_mcc_record->m_index == p_index) { + break; + } } - - cp->img_size = 0; - for(i=0;inumcomps ;i++){ - cp->img_size += (image->comps[i].w *image->comps[i].h * image->comps[i].prec); + + if (i==p_tcp->m_nb_mcc_records) { + /** element discarded **/ + return OPJ_TRUE; } + if (l_mcc_record->m_nb_comps != p_image->numcomps) { + /** do not support number of comps != image */ + return OPJ_TRUE; + } -#ifdef USE_JPWL - /* - calculate JPWL encoding parameters - */ + l_deco_array = l_mcc_record->m_decorrelation_array; - if (parameters->jpwl_epc_on) { - int i; + if (l_deco_array) { + l_data_size = MCT_ELEMENT_SIZE[l_deco_array->m_element_type] * p_image->numcomps * p_image->numcomps; + if (l_deco_array->m_data_size != l_data_size) { + return OPJ_FALSE; + } - /* set JPWL on */ - cp->epc_on = OPJ_TRUE; - cp->info_on = OPJ_FALSE; /* no informative technique */ + l_nb_elem = p_image->numcomps * p_image->numcomps; + l_mct_size = l_nb_elem * sizeof(OPJ_FLOAT32); + p_tcp->m_mct_decoding_matrix = (OPJ_FLOAT32*)opj_malloc(l_mct_size); - /* set EPB on */ - if ((parameters->jpwl_hprot_MH > 0) || (parameters->jpwl_hprot_TPH[0] > 0)) { - cp->epb_on = OPJ_TRUE; - - cp->hprot_MH = parameters->jpwl_hprot_MH; - for (i = 0; i < JPWL_MAX_NO_TILESPECS; i++) { - cp->hprot_TPH_tileno[i] = parameters->jpwl_hprot_TPH_tileno[i]; - cp->hprot_TPH[i] = parameters->jpwl_hprot_TPH[i]; - } - /* if tile specs are not specified, copy MH specs */ - if (cp->hprot_TPH[0] == -1) { - cp->hprot_TPH_tileno[0] = 0; - cp->hprot_TPH[0] = parameters->jpwl_hprot_MH; - } - for (i = 0; i < JPWL_MAX_NO_PACKSPECS; i++) { - cp->pprot_tileno[i] = parameters->jpwl_pprot_tileno[i]; - cp->pprot_packno[i] = parameters->jpwl_pprot_packno[i]; - cp->pprot[i] = parameters->jpwl_pprot[i]; - } + if (! p_tcp->m_mct_decoding_matrix ) { + return OPJ_FALSE; } - /* set ESD writing */ - if ((parameters->jpwl_sens_size == 1) || (parameters->jpwl_sens_size == 2)) { - cp->esd_on = OPJ_TRUE; + j2k_mct_read_functions_to_float[l_deco_array->m_element_type](l_deco_array->m_data,p_tcp->m_mct_decoding_matrix,l_nb_elem); + } - cp->sens_size = parameters->jpwl_sens_size; - cp->sens_addr = parameters->jpwl_sens_addr; - cp->sens_range = parameters->jpwl_sens_range; + l_offset_array = l_mcc_record->m_offset_array; - cp->sens_MH = parameters->jpwl_sens_MH; - for (i = 0; i < JPWL_MAX_NO_TILESPECS; i++) { - cp->sens_TPH_tileno[i] = parameters->jpwl_sens_TPH_tileno[i]; - cp->sens_TPH[i] = parameters->jpwl_sens_TPH[i]; - } + if (l_offset_array) { + l_data_size = MCT_ELEMENT_SIZE[l_offset_array->m_element_type] * p_image->numcomps; + if (l_offset_array->m_data_size != l_data_size) { + return OPJ_FALSE; } - /* always set RED writing to false: we are at the encoder */ - cp->red_on = OPJ_FALSE; + l_nb_elem = p_image->numcomps; + l_offset_size = l_nb_elem * sizeof(OPJ_UINT32); + l_offset_data = (OPJ_UINT32*)opj_malloc(l_offset_size); - } else { - cp->epc_on = OPJ_FALSE; - } -#endif /* USE_JPWL */ + if (! l_offset_data ) { + return OPJ_FALSE; + } + j2k_mct_read_functions_to_int32[l_offset_array->m_element_type](l_offset_array->m_data,l_offset_data,l_nb_elem); - /* initialize the mutiple tiles */ - /* ---------------------------- */ - cp->tcps = (opj_tcp_t*) opj_calloc(cp->tw * cp->th, sizeof(opj_tcp_t)); + l_tccp = p_tcp->tccps; + l_current_offset_data = l_offset_data; - for (tileno = 0; tileno < cp->tw * cp->th; tileno++) { - opj_tcp_t *tcp = &cp->tcps[tileno]; - tcp->numlayers = parameters->tcp_numlayers; - for (j = 0; j < tcp->numlayers; j++) { - if(cp->cinema){ - if (cp->fixed_quality) { - tcp->distoratio[j] = parameters->tcp_distoratio[j]; - } - tcp->rates[j] = parameters->tcp_rates[j]; - }else{ - if (cp->fixed_quality) { /* add fixed_quality */ - tcp->distoratio[j] = parameters->tcp_distoratio[j]; - } else { - tcp->rates[j] = parameters->tcp_rates[j]; - } - } + for (i=0;inumcomps;++i) { + l_tccp->m_dc_level_shift = *(l_current_offset_data++); + ++l_tccp; } - tcp->csty = parameters->csty; - tcp->prg = parameters->prog_order; - tcp->mct = parameters->tcp_mct; - numpocs_tile = 0; - tcp->POC = 0; - if (parameters->numpocs) { - /* initialisation of POC */ - tcp->POC = 1; - for (i = 0; i < parameters->numpocs; i++) { - if((tileno == parameters->POC[i].tile - 1) || (parameters->POC[i].tile == -1)) { - opj_poc_t *tcp_poc = &tcp->pocs[numpocs_tile]; - 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->prg1 = parameters->POC[numpocs_tile].prg1; - tcp_poc->tile = parameters->POC[numpocs_tile].tile; - numpocs_tile++; - } - } - tcp->numpocs = numpocs_tile -1 ; - }else{ - tcp->numpocs = 0; - } + opj_free(l_offset_data); + } - tcp->tccps = (opj_tccp_t*) opj_calloc(image->numcomps, sizeof(opj_tccp_t)); + return OPJ_TRUE; +} - for (i = 0; i < image->numcomps; i++) { - opj_tccp_t *tccp = &tcp->tccps[i]; - tccp->csty = parameters->csty & 0x01; /* 0 => one precinct || 1 => custom precinct */ - tccp->numresolutions = parameters->numresolution; - tccp->cblkw = int_floorlog2(parameters->cblockw_init); - tccp->cblkh = int_floorlog2(parameters->cblockh_init); - tccp->cblksty = parameters->mode; - tccp->qmfbid = parameters->irreversible ? 0 : 1; - tccp->qntsty = parameters->irreversible ? J2K_CCP_QNTSTY_SEQNT : J2K_CCP_QNTSTY_NOQNT; - tccp->numgbits = 2; - if (i == parameters->roi_compno) { - tccp->roishift = parameters->roi_shift; - } else { - tccp->roishift = 0; - } +/** + * Writes the CBD marker (Component bit depth definition) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +opj_bool j2k_write_cbd( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) +{ + OPJ_UINT32 i; + OPJ_UINT32 l_cbd_size; + OPJ_BYTE * l_current_data = 00; + opj_image_t *l_image = 00; + opj_image_comp_t * l_comp = 00; - if(parameters->cp_cinema) - { - //Precinct size for lowest frequency subband=128 - tccp->prcw[0] = 7; - tccp->prch[0] = 7; - //Precinct size at all other resolutions = 256 - for (j = 1; j < tccp->numresolutions; j++) { - tccp->prcw[j] = 8; - tccp->prch[j] = 8; - } - }else{ - if (parameters->csty & J2K_CCP_CSTY_PRT) { - int p = 0; - for (j = tccp->numresolutions - 1; j >= 0; j--) { - if (p < parameters->res_spec) { - - if (parameters->prcw_init[p] < 1) { - tccp->prcw[j] = 1; - } else { - tccp->prcw[j] = int_floorlog2(parameters->prcw_init[p]); - } - - if (parameters->prch_init[p] < 1) { - tccp->prch[j] = 1; - }else { - tccp->prch[j] = int_floorlog2(parameters->prch_init[p]); - } + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); - } else { - int res_spec = parameters->res_spec; - int size_prcw = parameters->prcw_init[res_spec - 1] >> (p - (res_spec - 1)); - int size_prch = parameters->prch_init[res_spec - 1] >> (p - (res_spec - 1)); - - if (size_prcw < 1) { - tccp->prcw[j] = 1; - } else { - tccp->prcw[j] = int_floorlog2(size_prcw); - } - - if (size_prch < 1) { - tccp->prch[j] = 1; - } else { - tccp->prch[j] = int_floorlog2(size_prch); - } - } - p++; - /*printf("\nsize precinct for level %d : %d,%d\n", j,tccp->prcw[j], tccp->prch[j]); */ - } //end for - } else { - for (j = 0; j < tccp->numresolutions; j++) { - tccp->prcw[j] = 15; - tccp->prch[j] = 15; - } - } - } + l_image = p_j2k->m_private_image; + l_cbd_size = 6 + p_j2k->m_private_image->numcomps; - dwt_calc_explicit_stepsizes(tccp, image->comps[i].prec); + if (l_cbd_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = (OPJ_BYTE*)opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_cbd_size); + + if (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) { + return OPJ_FALSE; } + + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_cbd_size; } -} -opj_bool j2k_encode(opj_j2k_t *j2k, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info) { - int tileno, compno; - opj_cp_t *cp = NULL; + l_current_data = p_j2k->m_specific_param.m_encoder.m_header_tile_data; - opj_tcd_t *tcd = NULL; /* TCD component */ + opj_write_bytes(l_current_data,J2K_MS_CBD,2); /* CBD */ + l_current_data += 2; - j2k->cio = cio; - j2k->image = image; + opj_write_bytes(l_current_data,l_cbd_size-2,2); /* L_CBD */ + l_current_data += 2; - cp = j2k->cp; + opj_write_bytes(l_current_data,l_image->numcomps, 2); /* Ncbd */ + l_current_data+=2; - /* INDEX >> */ - j2k->cstr_info = cstr_info; - if (cstr_info) { - int compno; - cstr_info->tile = (opj_tile_info_t *) opj_malloc(cp->tw * cp->th * sizeof(opj_tile_info_t)); - cstr_info->image_w = image->x1 - image->x0; - cstr_info->image_h = image->y1 - image->y0; - cstr_info->prog = (&cp->tcps[0])->prg; - cstr_info->tw = cp->tw; - cstr_info->th = cp->th; - cstr_info->tile_x = cp->tdx; /* new version parser */ - cstr_info->tile_y = cp->tdy; /* new version parser */ - cstr_info->tile_Ox = cp->tx0; /* new version parser */ - cstr_info->tile_Oy = cp->ty0; /* new version parser */ - cstr_info->numcomps = image->numcomps; - cstr_info->numlayers = (&cp->tcps[0])->numlayers; - cstr_info->numdecompos = (int*) opj_malloc(image->numcomps * sizeof(int)); - for (compno=0; compno < image->numcomps; compno++) { - cstr_info->numdecompos[compno] = (&cp->tcps[0])->tccps->numresolutions - 1; - } - cstr_info->D_max = 0.0; /* ADD Marcela */ - cstr_info->main_head_start = cio_tell(cio); /* position of SOC */ - cstr_info->maxmarknum = 100; - cstr_info->marker = (opj_marker_info_t *) opj_malloc(cstr_info->maxmarknum * sizeof(opj_marker_info_t)); - cstr_info->marknum = 0; + l_comp = l_image->comps; + + for (i=0;inumcomps;++i) { + opj_write_bytes(l_current_data, (l_comp->sgnd << 7) | (l_comp->prec - 1), 1); /* Component bit depth */ + ++l_current_data; + + ++l_comp; } - /* << INDEX */ - j2k_write_soc(j2k); - j2k_write_siz(j2k); - j2k_write_cod(j2k); - j2k_write_qcd(j2k); + if (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_cbd_size,p_manager) != l_cbd_size) { + return OPJ_FALSE; + } - if(cp->cinema){ - for (compno = 1; compno < image->numcomps; compno++) { - j2k_write_coc(j2k, compno); - j2k_write_qcc(j2k, compno); - } + return OPJ_TRUE; +} + +/** + * Reads a CBD marker (Component bit depth definition) + * @param p_header_data the data contained in the CBD box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the CBD marker. + * @param p_manager the user event manager. +*/ +opj_bool j2k_read_cbd ( opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager) +{ + OPJ_UINT32 l_nb_comp,l_num_comp; + OPJ_UINT32 l_comp_def; + OPJ_UINT32 i; + opj_image_comp_t * l_comp = 00; + + /* preconditions */ + assert(p_header_data != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + l_num_comp = p_j2k->m_private_image->numcomps; + + if (p_header_size != (p_j2k->m_private_image->numcomps + 2)) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Crror reading CBD marker\n"); + return OPJ_FALSE; } - for (compno = 0; compno < image->numcomps; compno++) { - opj_tcp_t *tcp = &cp->tcps[0]; - if (tcp->tccps[compno].roishift) - j2k_write_rgn(j2k, compno, 0); + opj_read_bytes(p_header_data,&l_nb_comp,2); /* Ncbd */ + p_header_data+=2; + + if (l_nb_comp != l_num_comp) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Crror reading CBD marker\n"); + return OPJ_FALSE; } - if (cp->comment != NULL) { - j2k_write_com(j2k); + + l_comp = p_j2k->m_private_image->comps; + for (i=0;isgnd = (l_comp_def>>7) & 1; + l_comp->prec = (l_comp_def&0x7f) + 1; + ++l_comp; } - j2k->totnum_tp = j2k_calculate_tp(cp,image->numcomps,image,j2k); - /* TLM Marker*/ - if(cp->cinema){ - j2k_write_tlm(j2k); - if (cp->cinema == CINEMA4K_24) { - j2k_write_poc(j2k); + return OPJ_TRUE; +} + + +/* ----------------------------------------------------------------------- */ +/* J2K / JPT decoder interface */ +/* ----------------------------------------------------------------------- */ + + + +void j2k_destroy_decompress(opj_j2k_t *j2k) { + int i = 0; + + if(j2k->tile_len != NULL) { + opj_free(j2k->tile_len); + } + if(j2k->tile_data != NULL) { + opj_free(j2k->tile_data); + } + if(j2k->default_tcp != NULL) { + opj_tcp_t *default_tcp = j2k->default_tcp; + if(default_tcp->ppt_data_first != NULL) { + opj_free(default_tcp->ppt_data_first); + } + if(j2k->default_tcp->tccps != NULL) { + opj_free(j2k->default_tcp->tccps); + } + opj_free(j2k->default_tcp); + } + if(j2k->cp != NULL) { + opj_cp_t *cp = j2k->cp; + if(cp->tcps != NULL) { + for(i = 0; i < cp->tw * cp->th; i++) { + if(cp->tcps[i].ppt_data_first != NULL) { + opj_free(cp->tcps[i].ppt_data_first); + } + if(cp->tcps[i].tccps != NULL) { + opj_free(cp->tcps[i].tccps); + } + } + opj_free(cp->tcps); + } + if(cp->ppm_data_first != NULL) { + opj_free(cp->ppm_data_first); + } + if(cp->tileno != NULL) { + opj_free(cp->tileno); + } + if(cp->comment != NULL) { + opj_free(cp->comment); } + + opj_free(cp); } + opj_free(j2k); +} - /* uncomment only for testing JPSEC marker writing */ - /* j2k_write_sec(j2k); */ - /* INDEX >> */ - if(cstr_info) { - cstr_info->main_head_end = cio_tell(cio) - 1; +void opj_j2k_setup_decoder(opj_j2k_v2_t *j2k, opj_dparameters_t *parameters) +{ + if(j2k && parameters) { + j2k->m_cp.m_specific_param.m_dec.m_layer = parameters->cp_layer; + j2k->m_cp.m_specific_param.m_dec.m_reduce = parameters->cp_reduce; + +#ifdef USE_JPWL + j2k->m_cp.correct = parameters->jpwl_correct; + j2k->m_cp.exp_comps = parameters->jpwl_exp_comps; + j2k->m_cp.max_tiles = parameters->jpwl_max_tiles; +#endif /* USE_JPWL */ } - /* << INDEX */ - /**** Main Header ENDS here ***/ +} - /* create the tile encoder */ - tcd = tcd_create(j2k->cinfo); +opj_image_t* j2k_decode(opj_j2k_t *j2k, opj_cio_t *cio, opj_codestream_info_t *cstr_info) { + opj_image_t *image = NULL; - /* encode each tile */ - for (tileno = 0; tileno < cp->tw * cp->th; tileno++) { - int pino; - int tilepartno=0; - /* UniPG>> */ - int acc_pack_num = 0; - /* <cinfo; + j2k->cio = cio; + j2k->cstr_info = cstr_info; + if (cstr_info) + memset(cstr_info, 0, sizeof(opj_codestream_info_t)); - opj_tcp_t *tcp = &cp->tcps[tileno]; - opj_event_msg(j2k->cinfo, EVT_INFO, "tile number %d / %d\n", tileno + 1, cp->tw * cp->th); + /* create an empty image */ + image = opj_image_create0(); + j2k->image = image; + + j2k->state = J2K_STATE_MHSOC; + + for (;;) { + opj_dec_mstabent_t *e; + int id = cio_read(cio, 2); + +#ifdef USE_JPWL + /* we try to honor JPWL correction power */ + if (j2k->cp->correct) { + + int orig_pos = cio_tell(cio); + opj_bool status; + + /* call the corrector */ + status = jpwl_correct(j2k); + + /* go back to where you were */ + cio_seek(cio, orig_pos - 2); + + /* re-read the marker */ + id = cio_read(cio, 2); + + /* check whether it begins with ff */ + if (id >> 8 != 0xff) { + opj_event_msg(cinfo, EVT_ERROR, + "JPWL: possible bad marker %x at %d\n", + id, cio_tell(cio) - 2); + if (!JPWL_ASSUME) { + opj_image_destroy(image); + opj_event_msg(cinfo, EVT_ERROR, "JPWL: giving up\n"); + return 0; + } + /* we try to correct */ + id = id | 0xff00; + cio_seek(cio, cio_tell(cio) - 2); + cio_write(cio, id, 2); + opj_event_msg(cinfo, EVT_WARNING, "- trying to adjust this\n" + "- setting marker to %x\n", + id); + } - j2k->curtileno = tileno; - j2k->cur_tp_num = 0; - tcd->cur_totnum_tp = j2k->cur_totnum_tp[j2k->curtileno]; - /* initialisation before tile encoding */ - if (tileno == 0) { - tcd_malloc_encode(tcd, image, cp, j2k->curtileno); - } else { - tcd_init_encode(tcd, image, cp, j2k->curtileno); } +#endif /* USE_JPWL */ - /* INDEX >> */ - if(cstr_info) { - cstr_info->tile[j2k->curtileno].start_pos = cio_tell(cio) + j2k->pos_correction; - cstr_info->tile[j2k->curtileno].maxmarknum = 10; - cstr_info->tile[j2k->curtileno].marker = (opj_marker_info_t *) opj_malloc(cstr_info->tile[j2k->curtileno].maxmarknum * sizeof(opj_marker_info_t)); - cstr_info->tile[j2k->curtileno].marknum = 0; + if (id >> 8 != 0xff) { + opj_image_destroy(image); + opj_event_msg(cinfo, EVT_ERROR, "%.8x: expected a marker instead of %x\n", cio_tell(cio) - 2, id); + return 0; } - /* << INDEX */ + e = j2k_dec_mstab_lookup(id); + /* Check if the marker is known*/ + if (!(j2k->state & e->states)) { + opj_image_destroy(image); + opj_event_msg(cinfo, EVT_ERROR, "%.8x: unexpected marker %x\n", cio_tell(cio) - 2, id); + return 0; + } + /* Check if the decoding is limited to the main header*/ + if (e->id == J2K_MS_SOT && j2k->cp->limit_decoding == LIMIT_TO_MAIN_HEADER) { + opj_event_msg(cinfo, EVT_INFO, "Main Header decoded.\n"); + return image; + } + + if (e->handler) { + (*e->handler)(j2k); + } + if (j2k->state & J2K_STATE_ERR) + return NULL; + + if (j2k->state == J2K_STATE_MT) { + break; + } + if (j2k->state == J2K_STATE_NEOC) { + break; + } + } + if (j2k->state == J2K_STATE_NEOC) { + j2k_read_eoc(j2k); + } + + if (j2k->state != J2K_STATE_MT) { + opj_event_msg(cinfo, EVT_WARNING, "Incomplete bitstream\n"); + } + return image; +} + +/* +* Read a JPT-stream and decode file +* +*/ +opj_image_t* j2k_decode_jpt_stream(opj_j2k_t *j2k, opj_cio_t *cio, opj_codestream_info_t *cstr_info) { + opj_image_t *image = NULL; + opj_jpt_msg_header_t header; + int position; + opj_common_ptr cinfo = j2k->cinfo; + + OPJ_ARG_NOT_USED(cstr_info); + + j2k->cio = cio; + + /* create an empty image */ + image = opj_image_create0(); + j2k->image = image; + + j2k->state = J2K_STATE_MHSOC; + + /* Initialize the header */ + jpt_init_msg_header(&header); + /* Read the first header of the message */ + jpt_read_msg_header(cinfo, cio, &header); + + position = cio_tell(cio); + if (header.Class_Id != 6) { /* 6 : Main header data-bin message */ + opj_image_destroy(image); + opj_event_msg(cinfo, EVT_ERROR, "[JPT-stream] : Expecting Main header first [class_Id %d] !\n", header.Class_Id); + return 0; + } + + for (;;) { + opj_dec_mstabent_t *e = NULL; + int id; + + if (!cio_numbytesleft(cio)) { + j2k_read_eoc(j2k); + return image; + } + /* data-bin read -> need to read a new header */ + if ((unsigned int) (cio_tell(cio) - position) == header.Msg_length) { + jpt_read_msg_header(cinfo, cio, &header); + position = cio_tell(cio); + if (header.Class_Id != 4) { /* 4 : Tile data-bin message */ + opj_image_destroy(image); + opj_event_msg(cinfo, EVT_ERROR, "[JPT-stream] : Expecting Tile info !\n"); + return 0; + } + } + + id = cio_read(cio, 2); + if (id >> 8 != 0xff) { + opj_image_destroy(image); + opj_event_msg(cinfo, EVT_ERROR, "%.8x: expected a marker instead of %x\n", cio_tell(cio) - 2, id); + return 0; + } + e = j2k_dec_mstab_lookup(id); + if (!(j2k->state & e->states)) { + opj_image_destroy(image); + opj_event_msg(cinfo, EVT_ERROR, "%.8x: unexpected marker %x\n", cio_tell(cio) - 2, id); + return 0; + } + if (e->handler) { + (*e->handler)(j2k); + } + if (j2k->state == J2K_STATE_MT) { + break; + } + if (j2k->state == J2K_STATE_NEOC) { + break; + } + } + if (j2k->state == J2K_STATE_NEOC) { + j2k_read_eoc(j2k); + } + + if (j2k->state != J2K_STATE_MT) { + opj_event_msg(cinfo, EVT_WARNING, "Incomplete bitstream\n"); + } + + return image; +} + +/* ----------------------------------------------------------------------- */ +/* J2K encoder interface */ +/* ----------------------------------------------------------------------- */ + +opj_j2k_t* j2k_create_compress(opj_common_ptr cinfo) { + opj_j2k_t *j2k = (opj_j2k_t*) opj_calloc(1, sizeof(opj_j2k_t)); + if(j2k) { + j2k->cinfo = cinfo; + } + return j2k; +} + +opj_j2k_v2_t* j2k_create_compress_v2(void) +{ + opj_j2k_v2_t *l_j2k = (opj_j2k_v2_t*) opj_malloc(sizeof(opj_j2k_v2_t)); + if (!l_j2k) { + return NULL; + } + + memset(l_j2k,0,sizeof(opj_j2k_v2_t)); + + l_j2k->m_is_decoder = 0; + l_j2k->m_cp.m_is_decoder = 0; + + l_j2k->m_specific_param.m_encoder.m_header_tile_data = (OPJ_BYTE *) opj_malloc(J2K_DEFAULT_HEADER_SIZE); + if (! l_j2k->m_specific_param.m_encoder.m_header_tile_data) { + j2k_destroy(l_j2k); + return NULL; + } + + l_j2k->m_specific_param.m_encoder.m_header_tile_data_size = J2K_DEFAULT_HEADER_SIZE; + + /* validation list creation*/ + l_j2k->m_validation_list = opj_procedure_list_create(); + if (! l_j2k->m_validation_list) { + j2k_destroy(l_j2k); + return NULL; + } + + /* execution list creation*/ + l_j2k->m_procedure_list = opj_procedure_list_create(); + if (! l_j2k->m_procedure_list) { + j2k_destroy(l_j2k); + return NULL; + } + + return l_j2k; +} + +void j2k_destroy_compress(opj_j2k_t *j2k) { + int tileno; + + if(!j2k) return; + if(j2k->cp != NULL) { + opj_cp_t *cp = j2k->cp; + + if(cp->comment) { + opj_free(cp->comment); + } + if(cp->matrice) { + opj_free(cp->matrice); + } + for (tileno = 0; tileno < cp->tw * cp->th; tileno++) { + opj_free(cp->tcps[tileno].tccps); + } + opj_free(cp->tcps); + opj_free(cp); + } + + opj_free(j2k); +} + +void j2k_setup_encoder(opj_j2k_t *j2k, opj_cparameters_t *parameters, opj_image_t *image) { + OPJ_UINT32 i,j; + int tileno, numpocs_tile; + opj_cp_t *cp = NULL; + + if(!j2k || !parameters || ! image) { + return; + } + + /* create and initialize the coding parameters structure */ + cp = (opj_cp_t*) opj_calloc(1, sizeof(opj_cp_t)); + + /* keep a link to cp so that we can destroy it later in j2k_destroy_compress */ + j2k->cp = cp; + + /* set default values for cp */ + cp->tw = 1; + cp->th = 1; + + /* + copy user encoding parameters + */ + cp->cinema = parameters->cp_cinema; + cp->max_comp_size = parameters->max_comp_size; + cp->rsiz = parameters->cp_rsiz; + cp->disto_alloc = parameters->cp_disto_alloc; + cp->fixed_alloc = parameters->cp_fixed_alloc; + cp->fixed_quality = parameters->cp_fixed_quality; + + /* mod fixed_quality */ + if(parameters->cp_matrice) { + size_t array_size = parameters->tcp_numlayers * parameters->numresolution * 3 * sizeof(int); + cp->matrice = (int *) opj_malloc(array_size); + memcpy(cp->matrice, parameters->cp_matrice, array_size); + } + + /* tiles */ + cp->tdx = parameters->cp_tdx; + cp->tdy = parameters->cp_tdy; + + /* tile offset */ + cp->tx0 = parameters->cp_tx0; + cp->ty0 = parameters->cp_ty0; + + /* comment string */ + if(parameters->cp_comment) { + cp->comment = (char*)opj_malloc(strlen(parameters->cp_comment) + 1); + if(cp->comment) { + strcpy(cp->comment, parameters->cp_comment); + } + } + + /* + calculate other encoding parameters + */ + + if (parameters->tile_size_on) { + cp->tw = int_ceildiv(image->x1 - cp->tx0, cp->tdx); + cp->th = int_ceildiv(image->y1 - cp->ty0, cp->tdy); + } else { + cp->tdx = image->x1 - cp->tx0; + cp->tdy = image->y1 - cp->ty0; + } + + if(parameters->tp_on){ + cp->tp_flag = parameters->tp_flag; + cp->tp_on = 1; + } + + cp->img_size = 0; + for(i=0;inumcomps ;i++){ + cp->img_size += (image->comps[i].w *image->comps[i].h * image->comps[i].prec); + } + + +#ifdef USE_JPWL + /* + calculate JPWL encoding parameters + */ + + if (parameters->jpwl_epc_on) { + OPJ_UINT32 i; + + /* set JPWL on */ + cp->epc_on = OPJ_TRUE; + cp->info_on = OPJ_FALSE; /* no informative technique */ + + /* set EPB on */ + if ((parameters->jpwl_hprot_MH > 0) || (parameters->jpwl_hprot_TPH[0] > 0)) { + cp->epb_on = OPJ_TRUE; + + cp->hprot_MH = parameters->jpwl_hprot_MH; + for (i = 0; i < JPWL_MAX_NO_TILESPECS; i++) { + cp->hprot_TPH_tileno[i] = parameters->jpwl_hprot_TPH_tileno[i]; + cp->hprot_TPH[i] = parameters->jpwl_hprot_TPH[i]; + } + /* if tile specs are not specified, copy MH specs */ + if (cp->hprot_TPH[0] == -1) { + cp->hprot_TPH_tileno[0] = 0; + cp->hprot_TPH[0] = parameters->jpwl_hprot_MH; + } + for (i = 0; i < JPWL_MAX_NO_PACKSPECS; i++) { + cp->pprot_tileno[i] = parameters->jpwl_pprot_tileno[i]; + cp->pprot_packno[i] = parameters->jpwl_pprot_packno[i]; + cp->pprot[i] = parameters->jpwl_pprot[i]; + } + } + + /* set ESD writing */ + if ((parameters->jpwl_sens_size == 1) || (parameters->jpwl_sens_size == 2)) { + cp->esd_on = OPJ_TRUE; + + cp->sens_size = parameters->jpwl_sens_size; + cp->sens_addr = parameters->jpwl_sens_addr; + cp->sens_range = parameters->jpwl_sens_range; + + cp->sens_MH = parameters->jpwl_sens_MH; + for (i = 0; i < JPWL_MAX_NO_TILESPECS; i++) { + cp->sens_TPH_tileno[i] = parameters->jpwl_sens_TPH_tileno[i]; + cp->sens_TPH[i] = parameters->jpwl_sens_TPH[i]; + } + } + + /* always set RED writing to false: we are at the encoder */ + cp->red_on = OPJ_FALSE; + + } else { + cp->epc_on = OPJ_FALSE; + } +#endif /* USE_JPWL */ + + + /* initialize the mutiple tiles */ + /* ---------------------------- */ + cp->tcps = (opj_tcp_t*) opj_calloc(cp->tw * cp->th, sizeof(opj_tcp_t)); + + for (tileno = 0; tileno < cp->tw * cp->th; tileno++) { + opj_tcp_t *tcp = &cp->tcps[tileno]; + tcp->numlayers = parameters->tcp_numlayers; + assert ( tcp->numlayers >= 0 ); + for (j = 0; j < (OPJ_UINT32)tcp->numlayers; j++) { + if(cp->cinema){ + if (cp->fixed_quality) { + tcp->distoratio[j] = parameters->tcp_distoratio[j]; + } + tcp->rates[j] = parameters->tcp_rates[j]; + }else{ + if (cp->fixed_quality) { /* add fixed_quality */ + tcp->distoratio[j] = parameters->tcp_distoratio[j]; + } else { + tcp->rates[j] = parameters->tcp_rates[j]; + } + } + } + tcp->csty = parameters->csty; + tcp->prg = parameters->prog_order; + tcp->mct = parameters->tcp_mct; + + numpocs_tile = 0; + tcp->POC = 0; + if (parameters->numpocs) { + /* initialisation of POC */ + tcp->POC = 1; + assert( parameters->numpocs >= 0 ); + for (i = 0; i < (OPJ_UINT32)parameters->numpocs; i++) { + if((tileno == parameters->POC[i].tile - 1) || (parameters->POC[i].tile == -1)) { + opj_poc_t *tcp_poc = &tcp->pocs[numpocs_tile]; + 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->prg1 = parameters->POC[numpocs_tile].prg1; + tcp_poc->tile = parameters->POC[numpocs_tile].tile; + numpocs_tile++; + } + } + tcp->numpocs = numpocs_tile -1 ; + }else{ + tcp->numpocs = 0; + } + + tcp->tccps = (opj_tccp_t*) opj_calloc(image->numcomps, sizeof(opj_tccp_t)); + + for (i = 0; i < image->numcomps; i++) { + opj_tccp_t *tccp = &tcp->tccps[i]; + tccp->csty = parameters->csty & 0x01; /* 0 => one precinct || 1 => custom precinct */ + tccp->numresolutions = parameters->numresolution; + tccp->cblkw = int_floorlog2(parameters->cblockw_init); + tccp->cblkh = int_floorlog2(parameters->cblockh_init); + tccp->cblksty = parameters->mode; + tccp->qmfbid = parameters->irreversible ? 0 : 1; + tccp->qntsty = parameters->irreversible ? J2K_CCP_QNTSTY_SEQNT : J2K_CCP_QNTSTY_NOQNT; + tccp->numgbits = 2; + assert(parameters->roi_compno >= 0); + if (i == (OPJ_UINT32)parameters->roi_compno) { + tccp->roishift = parameters->roi_shift; + } else { + tccp->roishift = 0; + } + + if(parameters->cp_cinema) + { + /*Precinct size for lowest frequency subband=128*/ + tccp->prcw[0] = 7; + tccp->prch[0] = 7; + /*Precinct size at all other resolutions = 256*/ + for (j = 1; j < tccp->numresolutions; j++) { + tccp->prcw[j] = 8; + tccp->prch[j] = 8; + } + }else{ + if (parameters->csty & J2K_CCP_CSTY_PRT) { + int p = 0; + assert(tccp->numresolutions > 0); + for (j = (OPJ_UINT32)(tccp->numresolutions - 1); (int)j >= 0; j--) { + if (p < parameters->res_spec) { + + if (parameters->prcw_init[p] < 1) { + tccp->prcw[j] = 1; + } else { + tccp->prcw[j] = int_floorlog2(parameters->prcw_init[p]); + } + + if (parameters->prch_init[p] < 1) { + tccp->prch[j] = 1; + }else { + tccp->prch[j] = int_floorlog2(parameters->prch_init[p]); + } + + } else { + int res_spec = parameters->res_spec; + int size_prcw = parameters->prcw_init[res_spec - 1] >> (p - (res_spec - 1)); + int size_prch = parameters->prch_init[res_spec - 1] >> (p - (res_spec - 1)); + + if (size_prcw < 1) { + tccp->prcw[j] = 1; + } else { + tccp->prcw[j] = int_floorlog2(size_prcw); + } + + if (size_prch < 1) { + tccp->prch[j] = 1; + } else { + tccp->prch[j] = int_floorlog2(size_prch); + } + } + p++; + /*printf("\nsize precinct for level %d : %d,%d\n", j,tccp->prcw[j], tccp->prch[j]); */ + } /*end for*/ + } else { + for (j = 0; j < tccp->numresolutions; j++) { + tccp->prcw[j] = 15; + tccp->prch[j] = 15; + } + } + } + + dwt_calc_explicit_stepsizes(tccp, image->comps[i].prec); + } + } +} + +void j2k_setup_encoder_v2( opj_j2k_v2_t *p_j2k, + opj_cparameters_t *parameters, + opj_image_t *image, + struct opj_event_mgr * p_manager) +{ + OPJ_UINT32 i, j, tileno, numpocs_tile; + opj_cp_v2_t *cp = 00; + opj_bool l_res; + + if(!p_j2k || !parameters || ! image) { + return; + } + + /* keep a link to cp so that we can destroy it later in j2k_destroy_compress */ + cp = &(p_j2k->m_cp); + + /* set default values for cp */ + cp->tw = 1; + cp->th = 1; + + /* + copy user encoding parameters + */ + cp->m_specific_param.m_enc.m_cinema = parameters->cp_cinema; + cp->m_specific_param.m_enc.m_max_comp_size = parameters->max_comp_size; + cp->rsiz = parameters->cp_rsiz; + cp->m_specific_param.m_enc.m_disto_alloc = parameters->cp_disto_alloc; + cp->m_specific_param.m_enc.m_fixed_alloc = parameters->cp_fixed_alloc; + cp->m_specific_param.m_enc.m_fixed_quality = parameters->cp_fixed_quality; + + /* mod fixed_quality */ + if (parameters->cp_matrice) { + size_t array_size = parameters->tcp_numlayers * parameters->numresolution * 3 * sizeof(OPJ_INT32); + cp->m_specific_param.m_enc.m_matrice = (OPJ_INT32 *) opj_malloc(array_size); + memcpy(cp->m_specific_param.m_enc.m_matrice, parameters->cp_matrice, array_size); + } + + /* tiles */ + cp->tdx = parameters->cp_tdx; + cp->tdy = parameters->cp_tdy; + + /* tile offset */ + cp->tx0 = parameters->cp_tx0; + cp->ty0 = parameters->cp_ty0; + + /* comment string */ + if(parameters->cp_comment) { + cp->comment = (char*)opj_malloc(strlen(parameters->cp_comment) + 1); + if(cp->comment) { + strcpy(cp->comment, parameters->cp_comment); + } + } + + /* + calculate other encoding parameters + */ + + if (parameters->tile_size_on) { + cp->tw = int_ceildiv(image->x1 - cp->tx0, cp->tdx); + cp->th = int_ceildiv(image->y1 - cp->ty0, cp->tdy); + } else { + cp->tdx = image->x1 - cp->tx0; + cp->tdy = image->y1 - cp->ty0; + } + + if (parameters->tp_on) { + cp->m_specific_param.m_enc.m_tp_flag = parameters->tp_flag; + cp->m_specific_param.m_enc.m_tp_on = 1; + } + +#ifdef USE_JPWL + /* + calculate JPWL encoding parameters + */ + + if (parameters->jpwl_epc_on) { + OPJ_INT32 i; + + /* set JPWL on */ + cp->epc_on = OPJ_TRUE; + cp->info_on = OPJ_FALSE; /* no informative technique */ + + /* set EPB on */ + if ((parameters->jpwl_hprot_MH > 0) || (parameters->jpwl_hprot_TPH[0] > 0)) { + cp->epb_on = OPJ_TRUE; + + cp->hprot_MH = parameters->jpwl_hprot_MH; + for (i = 0; i < JPWL_MAX_NO_TILESPECS; i++) { + cp->hprot_TPH_tileno[i] = parameters->jpwl_hprot_TPH_tileno[i]; + cp->hprot_TPH[i] = parameters->jpwl_hprot_TPH[i]; + } + /* if tile specs are not specified, copy MH specs */ + if (cp->hprot_TPH[0] == -1) { + cp->hprot_TPH_tileno[0] = 0; + cp->hprot_TPH[0] = parameters->jpwl_hprot_MH; + } + for (i = 0; i < JPWL_MAX_NO_PACKSPECS; i++) { + cp->pprot_tileno[i] = parameters->jpwl_pprot_tileno[i]; + cp->pprot_packno[i] = parameters->jpwl_pprot_packno[i]; + cp->pprot[i] = parameters->jpwl_pprot[i]; + } + } + + /* set ESD writing */ + if ((parameters->jpwl_sens_size == 1) || (parameters->jpwl_sens_size == 2)) { + cp->esd_on = OPJ_TRUE; + + cp->sens_size = parameters->jpwl_sens_size; + cp->sens_addr = parameters->jpwl_sens_addr; + cp->sens_range = parameters->jpwl_sens_range; + + cp->sens_MH = parameters->jpwl_sens_MH; + for (i = 0; i < JPWL_MAX_NO_TILESPECS; i++) { + cp->sens_TPH_tileno[i] = parameters->jpwl_sens_TPH_tileno[i]; + cp->sens_TPH[i] = parameters->jpwl_sens_TPH[i]; + } + } + + /* always set RED writing to false: we are at the encoder */ + cp->red_on = OPJ_FALSE; + + } else { + cp->epc_on = OPJ_FALSE; + } +#endif /* USE_JPWL */ + + + /* initialize the mutiple tiles */ + /* ---------------------------- */ + cp->tcps = (opj_tcp_v2_t*) opj_calloc(cp->tw * cp->th, sizeof(opj_tcp_v2_t)); + if (parameters->numpocs) { + /* initialisation of POC */ + l_res = j2k_check_poc_val(parameters->POC,parameters->numpocs, parameters->numresolution, image->numcomps, parameters->tcp_numlayers, p_manager); + // TODO + } + + for (tileno = 0; tileno < cp->tw * cp->th; tileno++) { + opj_tcp_v2_t *tcp = &cp->tcps[tileno]; + tcp->numlayers = parameters->tcp_numlayers; + + for (j = 0; j < tcp->numlayers; j++) { + if(cp->m_specific_param.m_enc.m_cinema){ + if (cp->m_specific_param.m_enc.m_fixed_quality) { + tcp->distoratio[j] = parameters->tcp_distoratio[j]; + } + tcp->rates[j] = parameters->tcp_rates[j]; + }else{ + if (cp->m_specific_param.m_enc.m_fixed_quality) { /* add fixed_quality */ + tcp->distoratio[j] = parameters->tcp_distoratio[j]; + } else { + tcp->rates[j] = parameters->tcp_rates[j]; + } + } + } + + tcp->csty = parameters->csty; + tcp->prg = parameters->prog_order; + tcp->mct = parameters->tcp_mct; + + numpocs_tile = 0; + tcp->POC = 0; + + if (parameters->numpocs) { + /* initialisation of POC */ + tcp->POC = 1; + // TODO + for (i = 0; i < (unsigned int) parameters->numpocs; i++) { + if((tileno == parameters->POC[i].tile - 1) || (parameters->POC[i].tile == -1)) { + opj_poc_t *tcp_poc = &tcp->pocs[numpocs_tile]; + + 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->prg1 = parameters->POC[numpocs_tile].prg1; + tcp_poc->tile = parameters->POC[numpocs_tile].tile; + + numpocs_tile++; + } + } + + tcp->numpocs = numpocs_tile -1 ; + }else{ + tcp->numpocs = 0; + } + + tcp->tccps = (opj_tccp_t*) opj_calloc(image->numcomps, sizeof(opj_tccp_t)); + + if (parameters->mct_data) { + + opj_event_msg_v2(p_manager, EVT_ERROR, "MCT not supported for now\n"); + return; + + /* TODO MSD : merge v2 add invert.c or used a external lib ? + OPJ_UINT32 lMctSize = image->numcomps * image->numcomps * sizeof(OPJ_FLOAT32); + OPJ_FLOAT32 * lTmpBuf = (OPJ_FLOAT32*)opj_malloc(lMctSize); + OPJ_INT32 * l_dc_shift = (OPJ_INT32 *) ((OPJ_BYTE *) parameters->mct_data + lMctSize); + + tcp->mct = 2; + tcp->m_mct_coding_matrix = (OPJ_FLOAT32*)opj_malloc(lMctSize); + memcpy(tcp->m_mct_coding_matrix,parameters->mct_data,lMctSize); + memcpy(lTmpBuf,parameters->mct_data,lMctSize); + + tcp->m_mct_decoding_matrix = (OPJ_FLOAT32*)opj_malloc(lMctSize); + assert(opj_matrix_inversion_f(lTmpBuf,(tcp->m_mct_decoding_matrix),image->numcomps)); + + tcp->mct_norms = (OPJ_FLOAT64*) + opj_malloc(image->numcomps * sizeof(OPJ_FLOAT64)); + + opj_calculate_norms(tcp->mct_norms,image->numcomps,tcp->m_mct_decoding_matrix); + opj_free(lTmpBuf); + + for (i = 0; i < image->numcomps; i++) { + opj_tccp_t *tccp = &tcp->tccps[i]; + tccp->m_dc_level_shift = l_dc_shift[i]; + } + + j2k_setup_mct_encoding(tcp,image); + */ + } + else { + for (i = 0; i < image->numcomps; i++) { + opj_tccp_t *tccp = &tcp->tccps[i]; + opj_image_comp_t * l_comp = &(image->comps[i]); + + if (! l_comp->sgnd) { + tccp->m_dc_level_shift = 1 << (l_comp->prec - 1); + } + } + } + + for (i = 0; i < image->numcomps; i++) { + opj_tccp_t *tccp = &tcp->tccps[i]; + + tccp->csty = parameters->csty & 0x01; /* 0 => one precinct || 1 => custom precinct */ + tccp->numresolutions = parameters->numresolution; + tccp->cblkw = int_floorlog2(parameters->cblockw_init); + tccp->cblkh = int_floorlog2(parameters->cblockh_init); + tccp->cblksty = parameters->mode; + tccp->qmfbid = parameters->irreversible ? 0 : 1; + tccp->qntsty = parameters->irreversible ? J2K_CCP_QNTSTY_SEQNT : J2K_CCP_QNTSTY_NOQNT; + tccp->numgbits = 2; + + if (i == parameters->roi_compno) { + tccp->roishift = parameters->roi_shift; + } else { + tccp->roishift = 0; + } + + if(parameters->cp_cinema) { + //Precinct size for lowest frequency subband=128 + tccp->prcw[0] = 7; + tccp->prch[0] = 7; + //Precinct size at all other resolutions = 256 + for (j = 1; j < tccp->numresolutions; j++) { + tccp->prcw[j] = 8; + tccp->prch[j] = 8; + } + }else{ + if (parameters->csty & J2K_CCP_CSTY_PRT) { + OPJ_INT32 p = 0, it_res; + for (it_res = tccp->numresolutions - 1; it_res >= 0; it_res--) { + if (p < parameters->res_spec) { + + if (parameters->prcw_init[p] < 1) { + tccp->prcw[it_res] = 1; + } else { + tccp->prcw[it_res] = int_floorlog2(parameters->prcw_init[p]); + } + + if (parameters->prch_init[p] < 1) { + tccp->prch[it_res] = 1; + }else { + tccp->prch[it_res] = int_floorlog2(parameters->prch_init[p]); + } + + } else { + int res_spec = parameters->res_spec; + int size_prcw = parameters->prcw_init[res_spec - 1] >> (p - (res_spec - 1)); + int size_prch = parameters->prch_init[res_spec - 1] >> (p - (res_spec - 1)); + + if (size_prcw < 1) { + tccp->prcw[it_res] = 1; + } else { + tccp->prcw[it_res] = int_floorlog2(size_prcw); + } + + if (size_prch < 1) { + tccp->prch[it_res] = 1; + } else { + tccp->prch[it_res] = int_floorlog2(size_prch); + } + } + p++; + /*printf("\nsize precinct for level %d : %d,%d\n", it_res,tccp->prcw[it_res], tccp->prch[it_res]); */ + } //end for + } else { + for (j = 0; j < tccp->numresolutions; j++) { + tccp->prcw[j] = 15; + tccp->prch[j] = 15; + } + } + } + + dwt_calc_explicit_stepsizes(tccp, image->comps[i].prec); + } + } + + if (parameters->mct_data) { + opj_free(parameters->mct_data); + parameters->mct_data = 00; + } +} + + +opj_bool j2k_encode(opj_j2k_t *j2k, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info) { + int tileno; + OPJ_UINT32 compno; + opj_cp_t *cp = NULL; + + opj_tcd_t *tcd = NULL; /* TCD component */ + + j2k->cio = cio; + j2k->image = image; + + cp = j2k->cp; + + /* INDEX >> */ + j2k->cstr_info = cstr_info; + if (cstr_info) { + OPJ_UINT32 compno; + cstr_info->tile = (opj_tile_info_t *) opj_malloc(cp->tw * cp->th * sizeof(opj_tile_info_t)); + cstr_info->image_w = image->x1 - image->x0; + cstr_info->image_h = image->y1 - image->y0; + cstr_info->prog = (&cp->tcps[0])->prg; + cstr_info->tw = cp->tw; + cstr_info->th = cp->th; + cstr_info->tile_x = cp->tdx; /* new version parser */ + cstr_info->tile_y = cp->tdy; /* new version parser */ + cstr_info->tile_Ox = cp->tx0; /* new version parser */ + cstr_info->tile_Oy = cp->ty0; /* new version parser */ + cstr_info->numcomps = image->numcomps; + cstr_info->numlayers = (&cp->tcps[0])->numlayers; + cstr_info->numdecompos = (int*) opj_malloc(image->numcomps * sizeof(int)); + for (compno=0; compno < image->numcomps; compno++) { + cstr_info->numdecompos[compno] = (&cp->tcps[0])->tccps->numresolutions - 1; + } + cstr_info->D_max = 0.0; /* ADD Marcela */ + cstr_info->main_head_start = cio_tell(cio); /* position of SOC */ + cstr_info->maxmarknum = 100; + cstr_info->marker = (opj_marker_info_t *) opj_malloc(cstr_info->maxmarknum * sizeof(opj_marker_info_t)); + cstr_info->marknum = 0; + } + /* << INDEX */ + + j2k_write_soc(j2k); + j2k_write_siz(j2k); + j2k_write_cod(j2k); + j2k_write_qcd(j2k); + + if(cp->cinema){ + for (compno = 1; compno < image->numcomps; compno++) { + j2k_write_coc(j2k, compno); + j2k_write_qcc(j2k, compno); + } + } + + for (compno = 0; compno < image->numcomps; compno++) { + opj_tcp_t *tcp = &cp->tcps[0]; + if (tcp->tccps[compno].roishift) + j2k_write_rgn(j2k, compno, 0); + } + if (cp->comment != NULL) { + j2k_write_com(j2k); + } + + j2k->totnum_tp = j2k_calculate_tp(cp,image->numcomps,image,j2k); + /* TLM Marker*/ + if(cp->cinema){ + j2k_write_tlm(j2k); + if (cp->cinema == CINEMA4K_24) { + j2k_write_poc(j2k); + } + } + + /* uncomment only for testing JPSEC marker writing */ + /* j2k_write_sec(j2k); */ + + /* INDEX >> */ + if(cstr_info) { + cstr_info->main_head_end = cio_tell(cio) - 1; + } + /* << INDEX */ + /**** Main Header ENDS here ***/ + + /* create the tile encoder */ + tcd = tcd_create(j2k->cinfo); + + /* encode each tile */ + for (tileno = 0; tileno < cp->tw * cp->th; tileno++) { + int pino; + int tilepartno=0; + /* UniPG>> */ + int acc_pack_num = 0; + /* <tcps[tileno]; + opj_event_msg(j2k->cinfo, EVT_INFO, "tile number %d / %d\n", tileno + 1, cp->tw * cp->th); + + j2k->curtileno = tileno; + j2k->cur_tp_num = 0; + tcd->cur_totnum_tp = j2k->cur_totnum_tp[j2k->curtileno]; + /* initialisation before tile encoding */ + if (tileno == 0) { + tcd_malloc_encode(tcd, image, cp, j2k->curtileno); + } else { + tcd_init_encode(tcd, image, cp, j2k->curtileno); + } + + /* INDEX >> */ + if(cstr_info) { + cstr_info->tile[j2k->curtileno].start_pos = cio_tell(cio) + j2k->pos_correction; + cstr_info->tile[j2k->curtileno].maxmarknum = 10; + cstr_info->tile[j2k->curtileno].marker = (opj_marker_info_t *) opj_malloc(cstr_info->tile[j2k->curtileno].maxmarknum * sizeof(opj_marker_info_t)); + cstr_info->tile[j2k->curtileno].marknum = 0; + } + /* << INDEX */ + + for(pino = 0; pino <= tcp->numpocs; pino++) { + int tot_num_tp; + tcd->cur_pino=pino; + + /*Get number of tile parts*/ + tot_num_tp = j2k_get_num_tp(cp,pino,tileno); + tcd->tp_pos = cp->tp_pos; + + for(tilepartno = 0; tilepartno < tot_num_tp ; tilepartno++){ + j2k->tp_num = tilepartno; + /* INDEX >> */ + if(cstr_info) + cstr_info->tile[j2k->curtileno].tp[j2k->cur_tp_num].tp_start_pos = + cio_tell(cio) + j2k->pos_correction; + /* << INDEX */ + j2k_write_sot(j2k); + + if(j2k->cur_tp_num == 0 && cp->cinema == 0){ + for (compno = 1; compno < image->numcomps; compno++) { + j2k_write_coc(j2k, compno); + j2k_write_qcc(j2k, compno); + } + if (cp->tcps[tileno].numpocs) { + j2k_write_poc(j2k); + } + } + + /* INDEX >> */ + if(cstr_info) + cstr_info->tile[j2k->curtileno].tp[j2k->cur_tp_num].tp_end_header = + cio_tell(cio) + j2k->pos_correction + 1; + /* << INDEX */ + + j2k_write_sod(j2k, tcd); + + /* INDEX >> */ + if(cstr_info) { + cstr_info->tile[j2k->curtileno].tp[j2k->cur_tp_num].tp_end_pos = + cio_tell(cio) + j2k->pos_correction - 1; + cstr_info->tile[j2k->curtileno].tp[j2k->cur_tp_num].tp_start_pack = + acc_pack_num; + cstr_info->tile[j2k->curtileno].tp[j2k->cur_tp_num].tp_numpacks = + cstr_info->packno - acc_pack_num; + acc_pack_num = cstr_info->packno; + } + /* << INDEX */ + + j2k->cur_tp_num++; + } + } + if(cstr_info) { + cstr_info->tile[j2k->curtileno].end_pos = cio_tell(cio) + j2k->pos_correction - 1; + } + + + /* + if (tile->PPT) { // BAD PPT !!! + FILE *PPT_file; + int i; + PPT_file=fopen("PPT","rb"); + fprintf(stderr,"%c%c%c%c",255,97,tile->len_ppt/256,tile->len_ppt%256); + for (i=0;ilen_ppt;i++) { + unsigned char elmt; + fread(&elmt, 1, 1, PPT_file); + fwrite(&elmt,1,1,f); + } + fclose(PPT_file); + unlink("PPT"); + } + */ + + } + + /* destroy the tile encoder */ + tcd_free_encode(tcd); + tcd_destroy(tcd); + + opj_free(j2k->cur_totnum_tp); + + j2k_write_eoc(j2k); + + if(cstr_info) { + cstr_info->codestream_size = cio_tell(cio) + j2k->pos_correction; + /* UniPG>> */ + /* The following adjustment is done to adjust the codestream size */ + /* if SOD is not at 0 in the buffer. Useful in case of JP2, where */ + /* the first bunch of bytes is not in the codestream */ + cstr_info->codestream_size -= cstr_info->main_head_start; + /* <epc_on) { + + /* encode according to JPWL */ + jpwl_encode(j2k, cio, image); + + } +#endif /* USE_JPWL */ + + return OPJ_TRUE; +} + +static void j2k_add_mhmarker(opj_codestream_info_t *cstr_info, unsigned short int type, int pos, int len) +{ + assert(cstr_info != 00); + + /* expand the list? */ + if ((cstr_info->marknum + 1) > cstr_info->maxmarknum) { + cstr_info->maxmarknum = 100 + (int) ((float) cstr_info->maxmarknum * 1.0F); + cstr_info->marker = (opj_marker_info_t*)opj_realloc(cstr_info->marker, cstr_info->maxmarknum); + } + + /* add the marker */ + cstr_info->marker[cstr_info->marknum].type = type; + cstr_info->marker[cstr_info->marknum].pos = pos; + cstr_info->marker[cstr_info->marknum].len = len; + cstr_info->marknum++; + +} + +static void j2k_add_mhmarker_v2(opj_codestream_index_t *cstr_index, OPJ_UINT32 type, OPJ_OFF_T pos, OPJ_UINT32 len) +{ + assert(cstr_index != 00); + + /* expand the list? */ + if ((cstr_index->marknum + 1) > cstr_index->maxmarknum) { + cstr_index->maxmarknum = 100 + (int) ((float) cstr_index->maxmarknum * 1.0F); + cstr_index->marker = (opj_marker_info_t*)opj_realloc(cstr_index->marker, cstr_index->maxmarknum *sizeof(opj_marker_info_t)); + } + + /* add the marker */ + cstr_index->marker[cstr_index->marknum].type = (OPJ_UINT16)type; + cstr_index->marker[cstr_index->marknum].pos = (OPJ_INT32)pos; + cstr_index->marker[cstr_index->marknum].len = (OPJ_INT32)len; + cstr_index->marknum++; + +} + +static void j2k_add_tlmarker( int tileno, opj_codestream_info_t *cstr_info, unsigned short int type, int pos, int len) +{ + opj_marker_info_t *marker; + + assert(cstr_info != 00); + + /* expand the list? */ + if ((cstr_info->tile[tileno].marknum + 1) > cstr_info->tile[tileno].maxmarknum) { + cstr_info->tile[tileno].maxmarknum = 100 + (int) ((float) cstr_info->tile[tileno].maxmarknum * 1.0F); + cstr_info->tile[tileno].marker = (opj_marker_info_t*)opj_realloc(cstr_info->tile[tileno].marker, cstr_info->maxmarknum); + } + + marker = &(cstr_info->tile[tileno].marker[cstr_info->tile[tileno].marknum]); + + /* add the marker */ + marker->type = type; + marker->pos = pos; + marker->len = len; + cstr_info->tile[tileno].marknum++; +} + +static void j2k_add_tlmarker_v2(OPJ_UINT32 tileno, opj_codestream_index_t *cstr_index, OPJ_UINT32 type, OPJ_OFF_T pos, OPJ_UINT32 len) +{ + assert(cstr_index != 00); + assert(cstr_index->tile_index != 00); + + /* expand the list? */ + if ((cstr_index->tile_index[tileno].marknum + 1) > cstr_index->tile_index[tileno].maxmarknum) { + cstr_index->tile_index[tileno].maxmarknum = 100 + (int) ((float) cstr_index->tile_index[tileno].maxmarknum * 1.0F); + cstr_index->tile_index[tileno].marker = + (opj_marker_info_t*)opj_realloc(cstr_index->tile_index[tileno].marker, + cstr_index->tile_index[tileno].maxmarknum *sizeof(opj_marker_info_t)); + } + + /* add the marker */ + cstr_index->tile_index[tileno].marker[cstr_index->tile_index[tileno].marknum].type = (OPJ_UINT16)type; + cstr_index->tile_index[tileno].marker[cstr_index->tile_index[tileno].marknum].pos = (OPJ_INT32)pos; + cstr_index->tile_index[tileno].marker[cstr_index->tile_index[tileno].marknum].len = (OPJ_INT32)len; + cstr_index->tile_index[tileno].marknum++; + + if (type == J2K_MS_SOT) { + OPJ_UINT32 l_current_tile_part = cstr_index->tile_index[tileno].current_tpsno; + + if (cstr_index->tile_index[tileno].tp_index) + cstr_index->tile_index[tileno].tp_index[l_current_tile_part].start_pos = pos; + + } +} + + +/* + * ----------------------------------------------------------------------- + * ----------------------------------------------------------------------- + * ----------------------------------------------------------------------- + */ + +/** + * Ends the decompression procedures and possibiliy add data to be read after the + * codestream. + */ +opj_bool j2k_end_decompress( + opj_j2k_v2_t *p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager) +{ + (void)p_j2k; + (void)p_stream; + (void)p_manager; + return OPJ_TRUE; +} + +/** + * Reads a jpeg2000 codestream header structure. + + * + * @param p_stream the stream to read data from. + * @param p_j2k the jpeg2000 codec. + * @param p_manager the user event manager. + * + * @return true if the box is valid. + */ +opj_bool j2k_read_header( struct opj_stream_private *p_stream, + opj_j2k_v2_t* p_j2k, + opj_image_t** p_image, + struct opj_event_mgr* p_manager ) +{ + /* preconditions */ + assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); + + /* create an empty image header */ + p_j2k->m_private_image = opj_image_create0(); + if (! p_j2k->m_private_image) { + return OPJ_FALSE; + } + + /* customization of the validation */ + j2k_setup_decoding_validation(p_j2k); + + /* validation of the parameters codec */ + if (! j2k_exec(p_j2k, p_j2k->m_validation_list, p_stream,p_manager)) { + opj_image_destroy(p_j2k->m_private_image); + p_j2k->m_private_image = NULL; + return OPJ_FALSE; + } + + /* customization of the encoding */ + j2k_setup_header_reading(p_j2k); + + /* read header */ + if (! j2k_exec (p_j2k,p_j2k->m_procedure_list,p_stream,p_manager)) { + opj_image_destroy(p_j2k->m_private_image); + p_j2k->m_private_image = NULL; + return OPJ_FALSE; + } + + *p_image = opj_image_create0(); + if (! (*p_image)) { + return OPJ_FALSE; + } + + /* Copy codestream image information to the output image */ + opj_copy_image_header(p_j2k->m_private_image, *p_image); + + /*Allocate and initialize some elements of codestrem index*/ + if (!j2k_allocate_tile_element_cstr_index(p_j2k)){ + return OPJ_FALSE; + } + + return OPJ_TRUE; +} + +/** + * Sets up the procedures to do on reading header. Developpers wanting to extend the library can add their own reading procedures. + */ +void j2k_setup_header_reading (opj_j2k_v2_t *p_j2k) +{ + /* preconditions*/ + assert(p_j2k != 00); + + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)j2k_read_header_procedure); + + /* DEVELOPER CORNER, add your custom procedures */ + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)j2k_copy_default_tcp_and_create_tcd); + +} + +/** + * 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. + */ +void j2k_setup_decoding_validation (opj_j2k_v2_t *p_j2k) +{ + /* preconditions*/ + assert(p_j2k != 00); + + opj_procedure_list_add_procedure(p_j2k->m_validation_list, (opj_procedure)j2k_build_decoder); + opj_procedure_list_add_procedure(p_j2k->m_validation_list, (opj_procedure)j2k_decoding_validation); + /* DEVELOPER CORNER, add your custom validation procedure */ + +} + + +/** + * The mct encoding validation procedure. + * + * @param p_j2k the jpeg2000 codec to validate. + * @param p_stream the input stream to validate. + * @param p_manager the user event manager. + * + * @return true if the parameters are correct. + */ +opj_bool j2k_mct_validation ( opj_j2k_v2_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ) +{ + opj_bool l_is_valid = OPJ_TRUE; + OPJ_UINT32 i,j; + + /* preconditions */ + assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); + + if ((p_j2k->m_cp.rsiz & 0x8200) == 0x8200) { + OPJ_UINT32 l_nb_tiles = p_j2k->m_cp.th * p_j2k->m_cp.tw; + opj_tcp_v2_t * l_tcp = p_j2k->m_cp.tcps; + + for (i=0;imct == 2) { + opj_tccp_t * l_tccp = l_tcp->tccps; + l_is_valid &= (l_tcp->m_mct_coding_matrix != 00); + + for (j=0;jm_private_image->numcomps;++j) { + l_is_valid &= ! (l_tccp->qmfbid & 1); + ++l_tccp; + } + } + ++l_tcp; + } + } + + return l_is_valid; +} + +opj_bool j2k_setup_mct_encoding(opj_tcp_v2_t * p_tcp, opj_image_t * p_image) +{ + OPJ_UINT32 i; + OPJ_UINT32 l_indix = 1; + opj_mct_data_t * l_mct_deco_data = 00,* l_mct_offset_data = 00; + opj_simple_mcc_decorrelation_data_t * l_mcc_data; + OPJ_UINT32 l_mct_size,l_nb_elem; + OPJ_FLOAT32 * l_data, * l_current_data; + opj_tccp_t * l_tccp; + + // preconditions + assert(p_tcp != 00); + + if (p_tcp->mct != 2) { + return OPJ_TRUE; + } + + if (p_tcp->m_mct_decoding_matrix) { + if (p_tcp->m_nb_mct_records == p_tcp->m_nb_max_mct_records) { + p_tcp->m_nb_max_mct_records += J2K_MCT_DEFAULT_NB_RECORDS; + + p_tcp->m_mct_records = (opj_mct_data_t*)opj_realloc(p_tcp->m_mct_records,p_tcp->m_nb_max_mct_records * sizeof(opj_mct_data_t)); + if (! p_tcp->m_mct_records) { + return OPJ_FALSE; + } + l_mct_deco_data = p_tcp->m_mct_records + p_tcp->m_nb_mct_records; + + memset(l_mct_deco_data ,0,(p_tcp->m_nb_max_mct_records - p_tcp->m_nb_mct_records) * sizeof(opj_mct_data_t)); + } + l_mct_deco_data = p_tcp->m_mct_records + p_tcp->m_nb_mct_records; + + if (l_mct_deco_data->m_data) { + opj_free(l_mct_deco_data->m_data); + l_mct_deco_data->m_data = 00; + } + + l_mct_deco_data->m_index = l_indix++; + l_mct_deco_data->m_array_type = MCT_TYPE_DECORRELATION; + l_mct_deco_data->m_element_type = MCT_TYPE_FLOAT; + l_nb_elem = p_image->numcomps * p_image->numcomps; + l_mct_size = l_nb_elem * MCT_ELEMENT_SIZE[l_mct_deco_data->m_element_type]; + l_mct_deco_data->m_data = (OPJ_BYTE*)opj_malloc(l_mct_size ); + + if (! l_mct_deco_data->m_data) { + return OPJ_FALSE; + } + + j2k_mct_write_functions_from_float[l_mct_deco_data->m_element_type](p_tcp->m_mct_decoding_matrix,l_mct_deco_data->m_data,l_nb_elem); + + l_mct_deco_data->m_data_size = l_mct_size; + ++p_tcp->m_nb_mct_records; + } + + if (p_tcp->m_nb_mct_records == p_tcp->m_nb_max_mct_records) { + p_tcp->m_nb_max_mct_records += J2K_MCT_DEFAULT_NB_RECORDS; + p_tcp->m_mct_records = (opj_mct_data_t*)opj_realloc(p_tcp->m_mct_records,p_tcp->m_nb_max_mct_records * sizeof(opj_mct_data_t)); + + if (! p_tcp->m_mct_records) { + return OPJ_FALSE; + } + + l_mct_offset_data = p_tcp->m_mct_records + p_tcp->m_nb_mct_records; + memset(l_mct_offset_data ,0,(p_tcp->m_nb_max_mct_records - p_tcp->m_nb_mct_records) * sizeof(opj_mct_data_t)); + + if (l_mct_deco_data) { + l_mct_deco_data = l_mct_offset_data - 1; + } + } + + l_mct_offset_data = p_tcp->m_mct_records + p_tcp->m_nb_mct_records; + + if (l_mct_offset_data->m_data) { + opj_free(l_mct_offset_data->m_data); + l_mct_offset_data->m_data = 00; + } + + l_mct_offset_data->m_index = l_indix++; + l_mct_offset_data->m_array_type = MCT_TYPE_OFFSET; + l_mct_offset_data->m_element_type = MCT_TYPE_FLOAT; + l_nb_elem = p_image->numcomps; + l_mct_size = l_nb_elem * MCT_ELEMENT_SIZE[l_mct_offset_data->m_element_type]; + l_mct_offset_data->m_data = (OPJ_BYTE*)opj_malloc(l_mct_size ); + + if (! l_mct_offset_data->m_data) { + return OPJ_FALSE; + } + + l_data = (OPJ_FLOAT32*)opj_malloc(l_nb_elem * sizeof(OPJ_FLOAT32)); + if (! l_data) { + opj_free(l_mct_offset_data->m_data); + l_mct_offset_data->m_data = 00; + return OPJ_FALSE; + } + + l_tccp = p_tcp->tccps; + l_current_data = l_data; + + for (i=0;im_dc_level_shift); + ++l_tccp; + } + + j2k_mct_write_functions_from_float[l_mct_offset_data->m_element_type](l_data,l_mct_offset_data->m_data,l_nb_elem); + + opj_free(l_data); + + l_mct_offset_data->m_data_size = l_mct_size; + + ++p_tcp->m_nb_mct_records; + + if (p_tcp->m_nb_mcc_records == p_tcp->m_nb_max_mcc_records) { + p_tcp->m_nb_max_mcc_records += J2K_MCT_DEFAULT_NB_RECORDS; + p_tcp->m_mcc_records = (opj_simple_mcc_decorrelation_data_t*) + opj_realloc(p_tcp->m_mcc_records,p_tcp->m_nb_max_mcc_records * sizeof(opj_simple_mcc_decorrelation_data_t)); + + if (! p_tcp->m_mcc_records) { + return OPJ_FALSE; + } + l_mcc_data = p_tcp->m_mcc_records + p_tcp->m_nb_mcc_records; + memset(l_mcc_data ,0,(p_tcp->m_nb_max_mcc_records - p_tcp->m_nb_mcc_records) * sizeof(opj_simple_mcc_decorrelation_data_t)); + + } + + l_mcc_data = p_tcp->m_mcc_records + p_tcp->m_nb_mcc_records; + l_mcc_data->m_decorrelation_array = l_mct_deco_data; + l_mcc_data->m_is_irreversible = 1; + l_mcc_data->m_nb_comps = p_image->numcomps; + l_mcc_data->m_index = l_indix++; + l_mcc_data->m_offset_array = l_mct_offset_data; + ++p_tcp->m_nb_mcc_records; + + return OPJ_TRUE; +} + +/** + * Builds the cp decoder parameters to use to decode tile. + */ +opj_bool j2k_build_decoder (opj_j2k_v2_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ) +{ + /* add here initialization of cp + copy paste of setup_decoder */ + (void)p_j2k; + (void)p_stream; + (void)p_manager; + return OPJ_TRUE; +} + +/** + * Builds the cp encoder parameters to use to encode tile. + */ +opj_bool j2k_build_encoder (opj_j2k_v2_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ) +{ + /* add here initialization of cp + copy paste of setup_encoder */ + (void)p_j2k; + (void)p_stream; + (void)p_manager; + return OPJ_TRUE; +} + +/** + * The default encoding validation procedure without any extension. + * + * @param p_j2k the jpeg2000 codec to validate. + * @param p_stream the input stream to validate. + * @param p_manager the user event manager. + * + * @return true if the parameters are correct. + */ +opj_bool j2k_encoding_validation ( opj_j2k_v2_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ) +{ + opj_bool l_is_valid = OPJ_TRUE; + + /* preconditions */ + assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); + + /* STATE checking */ + /* make sure the state is at 0 */ + l_is_valid &= (p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_NONE); + + /* POINTER validation */ + /* make sure a p_j2k codec is present */ + l_is_valid &= (p_j2k->m_procedure_list != 00); + /* make sure a validation list is present */ + l_is_valid &= (p_j2k->m_validation_list != 00); + + if ((p_j2k->m_cp.tdx) < (OPJ_UINT32) (1 << p_j2k->m_cp.tcps->tccps->numresolutions)) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Number of resolutions is too high in comparison to the size of tiles\n"); + return OPJ_FALSE; + } + + if ((p_j2k->m_cp.tdy) < (OPJ_UINT32) (1 << p_j2k->m_cp.tcps->tccps->numresolutions)) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Number of resolutions is too high in comparison to the size of tiles\n"); + return OPJ_FALSE; + } + + /* PARAMETER VALIDATION */ + return l_is_valid; +} + +/** + * The default decoding validation procedure without any extension. + * + * @param p_j2k the jpeg2000 codec to validate. + * @param p_stream the input stream to validate. + * @param p_manager the user event manager. + * + * @return true if the parameters are correct. + */ +opj_bool j2k_decoding_validation ( + opj_j2k_v2_t *p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ) +{ + opj_bool l_is_valid = OPJ_TRUE; + + /* preconditions*/ + assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); + + + /* STATE checking */ + /* make sure the state is at 0 */ +#ifdef TODO_MSD + l_is_valid &= (p_j2k->m_specific_param.m_decoder.m_state == J2K_DEC_STATE_NONE); +#endif + l_is_valid &= (p_j2k->m_specific_param.m_decoder.m_state == 0x0000); + + /* POINTER validation */ + /* make sure a p_j2k codec is present */ + /* make sure a procedure list is present */ + l_is_valid &= (p_j2k->m_procedure_list != 00); + /* make sure a validation list is present */ + l_is_valid &= (p_j2k->m_validation_list != 00); + + /* PARAMETER VALIDATION */ + return l_is_valid; +} + +opj_bool j2k_read_header_procedure( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager) +{ + OPJ_UINT32 l_current_marker; + OPJ_UINT32 l_marker_size; + const opj_dec_memory_marker_handler_t * l_marker_handler = 00; + + /* preconditions */ + assert(p_stream != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + /* We enter in the main header */ + p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_MHSOC; + + /* Try to read the SOC marker, the codestream must begin with SOC marker */ + if (! j2k_read_soc_v2(p_j2k,p_stream,p_manager)) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Expected a SOC marker \n"); + return OPJ_FALSE; + } + + /* 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_v2(p_manager, EVT_ERROR, "Stream too short\n"); + return OPJ_FALSE; + } + + /* Read 2 bytes as the new marker ID */ + opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data,&l_current_marker,2); + + /* Try to read until the SOT is detected */ + while (l_current_marker != J2K_MS_SOT) { + + /* Check if the current marker ID is valid */ + if (l_current_marker < 0xff00) { + opj_event_msg_v2(p_manager, EVT_ERROR, "We expected read a marker ID (0xff--) instead of %.8x\n", l_current_marker); + return OPJ_FALSE; + } + + /* Get the marker handler from the marker ID */ + l_marker_handler = j2k_get_marker_handler(l_current_marker); + + /* Manage case where marker is unknown */ + if (l_marker_handler->id == J2K_MS_UNK) { + if (! j2k_read_unk_v2(p_j2k, p_stream, &l_current_marker, p_manager)){ + opj_event_msg_v2(p_manager, EVT_ERROR, "Unknow marker have been detected and generated error.\n"); + return OPJ_FALSE; + } + + if (l_current_marker == J2K_MS_SOT) + break; /* SOT marker is detected main header is completely read */ + else /* Get the marker handler from the marker ID */ + l_marker_handler = j2k_get_marker_handler(l_current_marker); + } + + /* Check if the marker is known and if it is the right place to find it */ + if (! (p_j2k->m_specific_param.m_decoder.m_state & l_marker_handler->states) ) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Marker is not compliant with its position\n"); + return OPJ_FALSE; + } + + /* Try to read 2 bytes (the marker size) 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_v2(p_manager, EVT_ERROR, "Stream too short\n"); + return OPJ_FALSE; + } + + /* read 2 bytes as the marker size */ + opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data,&l_marker_size,2); + l_marker_size -= 2; /* Subtract the size of the marker ID already read */ + + /* Check if the marker size is compatible with the header data size */ + if (l_marker_size > p_j2k->m_specific_param.m_decoder.m_header_data_size) { + p_j2k->m_specific_param.m_decoder.m_header_data = (OPJ_BYTE*) + opj_realloc(p_j2k->m_specific_param.m_decoder.m_header_data,l_marker_size); + if (p_j2k->m_specific_param.m_decoder.m_header_data == 00) { + return OPJ_FALSE; + } + p_j2k->m_specific_param.m_decoder.m_header_data_size = l_marker_size; + } + + /* Try to read the rest of the marker segment 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,l_marker_size,p_manager) != l_marker_size) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Stream too short\n"); + return OPJ_FALSE; + } + + /* Read the marker segment with the correct marker handler */ + if (! (*(l_marker_handler->handler))(p_j2k,p_j2k->m_specific_param.m_decoder.m_header_data,l_marker_size,p_manager)) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Marker handler function failed to read the marker segment\n"); + return OPJ_FALSE; + } + + /* Add the marker to the codestream index*/ + j2k_add_mhmarker_v2(p_j2k->cstr_index, + l_marker_handler->id, + (OPJ_UINT32) opj_stream_tell(p_stream) - l_marker_size - 4, + l_marker_size + 4 ); + + /* 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_v2(p_manager, EVT_ERROR, "Stream too short\n"); + return OPJ_FALSE; + } + + /* read 2 bytes as the new marker ID */ + opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data,&l_current_marker,2); + } + + opj_event_msg_v2(p_manager, EVT_INFO, "Main header has been correctly decoded.\n"); + + /* Position of the last element if the main header */ + p_j2k->cstr_index->main_head_end = (OPJ_UINT32) opj_stream_tell(p_stream) - 2; + + /* Next step: read a tile-part header */ + p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_TPHSOT; + + return OPJ_TRUE; +} + +/** + * Excutes 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. + * @param p_stream the stream to execute the procedures on. + * @param p_manager the user manager. + * + * @return true if all the procedures were successfully executed. + */ +opj_bool j2k_exec ( opj_j2k_v2_t * p_j2k, + opj_procedure_list_t * p_procedure_list, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ) +{ + opj_bool (** l_procedure) (opj_j2k_v2_t * ,opj_stream_private_t *,opj_event_mgr_t *) = 00; + opj_bool l_result = OPJ_TRUE; + OPJ_UINT32 l_nb_proc, i; + + /* preconditions*/ + assert(p_procedure_list != 00); + assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); + + + l_nb_proc = opj_procedure_list_get_nb_procedures(p_procedure_list); + l_procedure = (opj_bool (**) (opj_j2k_v2_t * ,opj_stream_private_t *,opj_event_mgr_t *)) opj_procedure_list_get_first_procedure(p_procedure_list); + + for (i=0;im_private_image; + l_nb_tiles = p_j2k->m_cp.th * p_j2k->m_cp.tw; + l_tcp = p_j2k->m_cp.tcps; + l_tccp_size = l_image->numcomps * sizeof(opj_tccp_t); + l_default_tcp = p_j2k->m_specific_param.m_decoder.m_default_tcp; + l_mct_size = l_image->numcomps * l_image->numcomps * sizeof(OPJ_FLOAT32); + + /* For each tile */ + for (i=0; itccps; + /*Copy default coding parameters into the current tile coding parameters*/ + memcpy(l_tcp, l_default_tcp, sizeof(opj_tcp_v2_t)); + /* Initialize some values of the current tile coding parameters*/ + l_tcp->ppt = 0; + l_tcp->ppt_data = 00; + /* Reconnect the tile-compo coding parameters pointer to the current tile coding parameters*/ + l_tcp->tccps = l_current_tccp; + + /* Get the mct_decoding_matrix of the dflt_tile_cp and copy them into the current tile cp*/ + if (l_default_tcp->m_mct_decoding_matrix) { + l_tcp->m_mct_decoding_matrix = (OPJ_FLOAT32*)opj_malloc(l_mct_size); + if (! l_tcp->m_mct_decoding_matrix ) { + return OPJ_FALSE; + } + memcpy(l_tcp->m_mct_decoding_matrix,l_default_tcp->m_mct_decoding_matrix,l_mct_size); + } + + /* Get the mct_record of the dflt_tile_cp and copy them into the current tile cp*/ + l_mct_records_size = l_default_tcp->m_nb_max_mct_records * sizeof(opj_mct_data_t); + l_tcp->m_mct_records = (opj_mct_data_t*)opj_malloc(l_mct_records_size); + if (! l_tcp->m_mct_records) { + return OPJ_FALSE; + } + memcpy(l_tcp->m_mct_records, l_default_tcp->m_mct_records,l_mct_records_size); + + /* Copy the mct record data from dflt_tile_cp to the current tile*/ + l_src_mct_rec = l_default_tcp->m_mct_records; + l_dest_mct_rec = l_tcp->m_mct_records; + + for (j=0;jm_nb_mct_records;++j) { + + if (l_src_mct_rec->m_data) { + + l_dest_mct_rec->m_data = (OPJ_BYTE*) opj_malloc(l_src_mct_rec->m_data_size); + if(! l_dest_mct_rec->m_data) { + return OPJ_FALSE; + } + memcpy(l_dest_mct_rec->m_data,l_src_mct_rec->m_data,l_src_mct_rec->m_data_size); + } + + ++l_src_mct_rec; + ++l_dest_mct_rec; + } + + /* Get the mcc_record of the dflt_tile_cp and copy them into the current tile cp*/ + l_mcc_records_size = l_default_tcp->m_nb_max_mcc_records * sizeof(opj_simple_mcc_decorrelation_data_t); + l_tcp->m_mcc_records = (opj_simple_mcc_decorrelation_data_t*) opj_malloc(l_mcc_records_size); + if (! l_tcp->m_mcc_records) { + return OPJ_FALSE; + } + memcpy(l_tcp->m_mcc_records,l_default_tcp->m_mcc_records,l_mcc_records_size); + + /* Copy the mcc record data from dflt_tile_cp to the current tile*/ + l_src_mcc_rec = l_default_tcp->m_mcc_records; + l_dest_mcc_rec = l_tcp->m_mcc_records; + + for (j=0;jm_nb_max_mcc_records;++j) { + + if (l_src_mcc_rec->m_decorrelation_array) { + l_offset = l_src_mcc_rec->m_decorrelation_array - l_default_tcp->m_mct_records; + l_dest_mcc_rec->m_decorrelation_array = l_tcp->m_mct_records + l_offset; + } + + if (l_src_mcc_rec->m_offset_array) { + l_offset = l_src_mcc_rec->m_offset_array - l_default_tcp->m_mct_records; + l_dest_mcc_rec->m_offset_array = l_tcp->m_mct_records + l_offset; + } + + ++l_src_mcc_rec; + ++l_dest_mcc_rec; + } + + /* Copy all the dflt_tile_compo_cp to the current tile cp */ + memcpy(l_current_tccp,l_default_tcp->tccps,l_tccp_size); + + /* Move to next tile cp*/ + ++l_tcp; + } + + /* Create the current tile decoder*/ + p_j2k->m_tcd = (opj_tcd_v2_t*)tcd_create_v2(OPJ_TRUE); /* FIXME why a cast ? */ + if (! p_j2k->m_tcd ) { + return OPJ_FALSE; + } + + if ( !tcd_init_v2(p_j2k->m_tcd, l_image, &(p_j2k->m_cp)) ) { + tcd_destroy_v2(p_j2k->m_tcd); + p_j2k->m_tcd = 00; + opj_event_msg_v2(p_manager, EVT_ERROR, "Cannot decode tile, memory error\n"); + return OPJ_FALSE; + } + + return OPJ_TRUE; +} + +/** + * Reads the lookup table containing all the marker, status and action, and returns the handler associated + * with the marker value. + * @param p_id Marker value to look up + * + * @return the handler associated with the id. +*/ +const opj_dec_memory_marker_handler_t * j2k_get_marker_handler (OPJ_UINT32 p_id) +{ + const opj_dec_memory_marker_handler_t *e; + for (e = j2k_memory_marker_handler_tab; e->id != 0; ++e) { + if (e->id == p_id) { + break; /* we find a handler corresponding to the marker ID*/ + } + } + return e; +} + + +/** + * Destroys a jpeg2000 codec. + * + * @param p_j2k the jpeg20000 structure to destroy. + */ +void j2k_destroy (opj_j2k_v2_t *p_j2k) +{ + if (p_j2k == 00) { + return; + } + + if (p_j2k->m_is_decoder) { + + if (p_j2k->m_specific_param.m_decoder.m_default_tcp != 00) { + j2k_tcp_destroy(p_j2k->m_specific_param.m_decoder.m_default_tcp); + opj_free(p_j2k->m_specific_param.m_decoder.m_default_tcp); + p_j2k->m_specific_param.m_decoder.m_default_tcp = 00; + } + + if (p_j2k->m_specific_param.m_decoder.m_header_data != 00) { + opj_free(p_j2k->m_specific_param.m_decoder.m_header_data); + p_j2k->m_specific_param.m_decoder.m_header_data = 00; + p_j2k->m_specific_param.m_decoder.m_header_data_size = 0; + } + } + else { + + if (p_j2k->m_specific_param.m_encoder.m_encoded_tile_data) { + opj_free(p_j2k->m_specific_param.m_encoder.m_encoded_tile_data); + p_j2k->m_specific_param.m_encoder.m_encoded_tile_data = 00; + } + + if (p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer) { + opj_free(p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer); + p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer = 00; + p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current = 00; + } + + if (p_j2k->m_specific_param.m_encoder.m_header_tile_data) { + opj_free(p_j2k->m_specific_param.m_encoder.m_header_tile_data); + p_j2k->m_specific_param.m_encoder.m_header_tile_data = 00; + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = 0; + } + } + + tcd_destroy_v2(p_j2k->m_tcd); + + j2k_cp_destroy(&(p_j2k->m_cp)); + memset(&(p_j2k->m_cp),0,sizeof(opj_cp_v2_t)); + + opj_procedure_list_destroy(p_j2k->m_procedure_list); + p_j2k->m_procedure_list = 00; + + opj_procedure_list_destroy(p_j2k->m_validation_list); + p_j2k->m_procedure_list = 00; + + j2k_destroy_cstr_index(p_j2k->cstr_index); + p_j2k->cstr_index = NULL; + + opj_image_destroy(p_j2k->m_private_image); + p_j2k->m_private_image = NULL; + + opj_image_destroy(p_j2k->m_output_image); + p_j2k->m_output_image = NULL; + + opj_free(p_j2k); +} + +void j2k_destroy_cstr_index (opj_codestream_index_t *p_cstr_ind) +{ + if (p_cstr_ind) { + + if (p_cstr_ind->marker) { + opj_free(p_cstr_ind->marker); + p_cstr_ind->marker = NULL; + } + + if (p_cstr_ind->tile_index) { + OPJ_UINT32 it_tile = 0; + + for (it_tile=0; it_tile < p_cstr_ind->nb_of_tiles; it_tile++) { + + if(p_cstr_ind->tile_index[it_tile].packet_index) { + opj_free(p_cstr_ind->tile_index[it_tile].packet_index); + p_cstr_ind->tile_index[it_tile].packet_index = NULL; + } + + if(p_cstr_ind->tile_index[it_tile].tp_index){ + opj_free(p_cstr_ind->tile_index[it_tile].tp_index); + p_cstr_ind->tile_index[it_tile].tp_index = NULL; + } + + if(p_cstr_ind->tile_index[it_tile].marker){ + opj_free(p_cstr_ind->tile_index[it_tile].marker); + p_cstr_ind->tile_index[it_tile].marker = NULL; + + } + } + + opj_free( p_cstr_ind->tile_index); + p_cstr_ind->tile_index = NULL; + } + + opj_free(p_cstr_ind); + } +} + + + +/** + * Destroys a tile coding parameter structure. + * + * @param p_tcp the tile coding parameter to destroy. + */ +void j2k_tcp_destroy (opj_tcp_v2_t *p_tcp) +{ + if (p_tcp == 00) { + return; + } + + if (p_tcp->ppt_buffer != 00) { + opj_free(p_tcp->ppt_buffer); + p_tcp->ppt_buffer = 00; + } + + if (p_tcp->tccps != 00) { + opj_free(p_tcp->tccps); + p_tcp->tccps = 00; + } + + if (p_tcp->m_mct_coding_matrix != 00) { + opj_free(p_tcp->m_mct_coding_matrix); + p_tcp->m_mct_coding_matrix = 00; + } + + if (p_tcp->m_mct_decoding_matrix != 00) { + opj_free(p_tcp->m_mct_decoding_matrix); + p_tcp->m_mct_decoding_matrix = 00; + } + + if (p_tcp->m_mcc_records) { + opj_free(p_tcp->m_mcc_records); + p_tcp->m_mcc_records = 00; + p_tcp->m_nb_max_mcc_records = 0; + p_tcp->m_nb_mcc_records = 0; + } + + if (p_tcp->m_mct_records) { + opj_mct_data_t * l_mct_data = p_tcp->m_mct_records; + OPJ_UINT32 i; + + for (i=0;im_nb_mct_records;++i) { + if (l_mct_data->m_data) { + opj_free(l_mct_data->m_data); + l_mct_data->m_data = 00; + } + + ++l_mct_data; + } + + opj_free(p_tcp->m_mct_records); + p_tcp->m_mct_records = 00; + } + + if (p_tcp->mct_norms != 00) { + opj_free(p_tcp->mct_norms); + p_tcp->mct_norms = 00; + } + + j2k_tcp_data_destroy(p_tcp); + +} + +/** + * Destroys the data inside a tile coding parameter structure. + * + * @param p_tcp the tile coding parameter which contain data to destroy. + */ +void j2k_tcp_data_destroy (opj_tcp_v2_t *p_tcp) +{ + if (p_tcp->m_data) { + opj_free(p_tcp->m_data); + p_tcp->m_data = NULL; + p_tcp->m_data_size = 0; + } +} + +/** + * Destroys a coding parameter structure. + * + * @param p_cp the coding parameter to destroy. + */ +void j2k_cp_destroy (opj_cp_v2_t *p_cp) +{ + OPJ_UINT32 l_nb_tiles; + opj_tcp_v2_t * l_current_tile = 00; + OPJ_UINT32 i; + + if + (p_cp == 00) + { + return; + } + if + (p_cp->tcps != 00) + { + l_current_tile = p_cp->tcps; + l_nb_tiles = p_cp->th * p_cp->tw; + + for + (i = 0; i < l_nb_tiles; ++i) + { + j2k_tcp_destroy(l_current_tile); + ++l_current_tile; + } + opj_free(p_cp->tcps); + p_cp->tcps = 00; + } + if + (p_cp->ppm_buffer != 00) + { + opj_free(p_cp->ppm_buffer); + p_cp->ppm_buffer = 00; + } + if + (p_cp->comment != 00) + { + opj_free(p_cp->comment); + p_cp->comment = 00; + } + if + (! p_cp->m_is_decoder) + { + if + (p_cp->m_specific_param.m_enc.m_matrice) + { + opj_free(p_cp->m_specific_param.m_enc.m_matrice); + p_cp->m_specific_param.m_enc.m_matrice = 00; + } + } +} + + + +/** + * Reads a tile header. + * @param p_j2k the jpeg2000 codec. + * @param p_stream the stream to write data to. + * @param p_manager the user event manager. + */ +opj_bool j2k_read_tile_header( opj_j2k_v2_t * p_j2k, + OPJ_UINT32 * p_tile_index, + OPJ_UINT32 * p_data_size, + OPJ_INT32 * p_tile_x0, OPJ_INT32 * p_tile_y0, + OPJ_INT32 * p_tile_x1, OPJ_INT32 * p_tile_y1, + OPJ_UINT32 * p_nb_comps, + opj_bool * p_go_on, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ) +{ + OPJ_UINT32 l_current_marker = J2K_MS_SOT; + OPJ_UINT32 l_marker_size; + const opj_dec_memory_marker_handler_t * l_marker_handler = 00; + opj_tcp_v2_t * l_tcp = NULL; + OPJ_UINT32 l_nb_tiles; + + /* preconditions */ + assert(p_stream != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + /* Reach the End Of Codestream ?*/ + if (p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_EOC){ + l_current_marker = J2K_MS_EOC; + } + /* We need to encounter a SOT marker (a new tile-part header) */ + else if (p_j2k->m_specific_param.m_decoder.m_state != J2K_STATE_TPHSOT){ + return OPJ_FALSE; + } + + /* Read into the codestream until reach the EOC or ! can_decode ??? FIXME */ + while ( (!p_j2k->m_specific_param.m_decoder.m_can_decode) && (l_current_marker != J2K_MS_EOC) ) { + + /* Try to read until the Start Of Data is detected */ + while (l_current_marker != J2K_MS_SOD) { + + /* Try to read 2 bytes (the marker size) 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_v2(p_manager, EVT_ERROR, "Stream too short\n"); + return OPJ_FALSE; + } + + /* Read 2 bytes from the buffer as the marker size */ + opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data,&l_marker_size,2); + + /* Why this condition? FIXME */ + if (p_j2k->m_specific_param.m_decoder.m_state & J2K_STATE_TPH){ + p_j2k->m_specific_param.m_decoder.m_sot_length -= (l_marker_size + 2); + } + l_marker_size -= 2; /* Subtract the size of the marker ID already read */ + + /* Get the marker handler from the marker ID */ + l_marker_handler = j2k_get_marker_handler(l_current_marker); + + /* Check if the marker is known and if it is the right place to find it */ + if (! (p_j2k->m_specific_param.m_decoder.m_state & l_marker_handler->states) ) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Marker is not compliant with its position\n"); + return OPJ_FALSE; + } +/* FIXME manage case of unknown marker as in the main header ? */ + + /* Check if the marker size is compatible with the header data size */ + if (l_marker_size > p_j2k->m_specific_param.m_decoder.m_header_data_size) { + p_j2k->m_specific_param.m_decoder.m_header_data = (OPJ_BYTE*) + opj_realloc(p_j2k->m_specific_param.m_decoder.m_header_data,l_marker_size); + if (p_j2k->m_specific_param.m_decoder.m_header_data == 00) { + return OPJ_FALSE; + } + p_j2k->m_specific_param.m_decoder.m_header_data_size = l_marker_size; + } + + /* Try to read the rest of the marker segment 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,l_marker_size,p_manager) != l_marker_size) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Stream too short\n"); + return OPJ_FALSE; + } - for(pino = 0; pino <= tcp->numpocs; pino++) { - int tot_num_tp; - tcd->cur_pino=pino; + /* Read the marker segment with the correct marker handler */ + if (! (*(l_marker_handler->handler))(p_j2k,p_j2k->m_specific_param.m_decoder.m_header_data,l_marker_size,p_manager)) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Fail to read the current marker segment (%#x)\n", l_current_marker); + return OPJ_FALSE; + } - /*Get number of tile parts*/ - tot_num_tp = j2k_get_num_tp(cp,pino,tileno); - tcd->tp_pos = cp->tp_pos; + /* Add the marker to the codestream index*/ + j2k_add_tlmarker_v2(p_j2k->m_current_tile_number, + p_j2k->cstr_index, + l_marker_handler->id, + (OPJ_UINT32) opj_stream_tell(p_stream) - l_marker_size - 4, + l_marker_size + 4 ); - for(tilepartno = 0; tilepartno < tot_num_tp ; tilepartno++){ - j2k->tp_num = tilepartno; - /* INDEX >> */ - if(cstr_info) - cstr_info->tile[j2k->curtileno].tp[j2k->cur_tp_num].tp_start_pos = - cio_tell(cio) + j2k->pos_correction; - /* << INDEX */ - j2k_write_sot(j2k); + /* Keep the position of the last SOT marker read */ + if ( l_marker_handler->id == J2K_MS_SOT ) { + OPJ_UINT32 sot_pos = (OPJ_UINT32) opj_stream_tell(p_stream) - l_marker_size - 4 ; + if (sot_pos > p_j2k->m_specific_param.m_decoder.m_last_sot_read_pos) + { + p_j2k->m_specific_param.m_decoder.m_last_sot_read_pos = sot_pos; + } + } - if(j2k->cur_tp_num == 0 && cp->cinema == 0){ - for (compno = 1; compno < image->numcomps; compno++) { - j2k_write_coc(j2k, compno); - j2k_write_qcc(j2k, compno); - } - if (cp->tcps[tileno].numpocs) { - j2k_write_poc(j2k); - } + + if (p_j2k->m_specific_param.m_decoder.m_skip_data) { + /* Skip the rest of the tile part header*/ + if (opj_stream_skip(p_stream,p_j2k->m_specific_param.m_decoder.m_sot_length,p_manager) != p_j2k->m_specific_param.m_decoder.m_sot_length) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Stream too short\n"); + return OPJ_FALSE; + } + l_current_marker = J2K_MS_SOD; /* Normally we reached a SOD */ + } + else { + /* 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_v2(p_manager, EVT_ERROR, "Stream too short\n"); + return OPJ_FALSE; } + /* Read 2 bytes from the buffer as the new marker ID */ + opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data,&l_current_marker,2); + } + } - /* INDEX >> */ - if(cstr_info) - cstr_info->tile[j2k->curtileno].tp[j2k->cur_tp_num].tp_end_header = - cio_tell(cio) + j2k->pos_correction + 1; - /* << INDEX */ + /* If we didn't skip data before, we need to read the SOD marker*/ + if (! p_j2k->m_specific_param.m_decoder.m_skip_data) { + /* Try to read the SOD marker and skip data ? FIXME */ + if (! j2k_read_sod_v2(p_j2k, p_stream, p_manager)) { + return OPJ_FALSE; + } - j2k_write_sod(j2k, tcd); - /* INDEX >> */ - if(cstr_info) { - cstr_info->tile[j2k->curtileno].tp[j2k->cur_tp_num].tp_end_pos = - cio_tell(cio) + j2k->pos_correction - 1; - cstr_info->tile[j2k->curtileno].tp[j2k->cur_tp_num].tp_start_pack = - acc_pack_num; - cstr_info->tile[j2k->curtileno].tp[j2k->cur_tp_num].tp_numpacks = - cstr_info->packno - acc_pack_num; - acc_pack_num = cstr_info->packno; + + 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_v2(p_manager, EVT_ERROR, "Stream too short\n"); + return OPJ_FALSE; } - /* << INDEX */ - j2k->cur_tp_num++; - } - } - if(cstr_info) { - cstr_info->tile[j2k->curtileno].end_pos = cio_tell(cio) + j2k->pos_correction - 1; + /* 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; + /* 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_v2(p_manager, EVT_ERROR, "Stream too short\n"); + return OPJ_FALSE; + } - /* - if (tile->PPT) { // BAD PPT !!! - FILE *PPT_file; - int i; - PPT_file=fopen("PPT","rb"); - fprintf(stderr,"%c%c%c%c",255,97,tile->len_ppt/256,tile->len_ppt%256); - for (i=0;ilen_ppt;i++) { - unsigned char elmt; - fread(&elmt, 1, 1, PPT_file); - fwrite(&elmt,1,1,f); - } - fclose(PPT_file); - unlink("PPT"); + /* 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); } - */ + } + /* Current marker is the EOC marker ?*/ + if (l_current_marker == J2K_MS_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; + } } - /* destroy the tile encoder */ - tcd_free_encode(tcd); - tcd_destroy(tcd); + /* FIXME DOC ???*/ + if ( ! p_j2k->m_specific_param.m_decoder.m_can_decode) { + l_tcp = p_j2k->m_cp.tcps + p_j2k->m_current_tile_number; + l_nb_tiles = p_j2k->m_cp.th * p_j2k->m_cp.tw; - opj_free(j2k->cur_totnum_tp); + while( (p_j2k->m_current_tile_number < l_nb_tiles) && (l_tcp->m_data == 00) ) { + ++p_j2k->m_current_tile_number; + ++l_tcp; + } - j2k_write_eoc(j2k); + if (p_j2k->m_current_tile_number == l_nb_tiles) { + *p_go_on = OPJ_FALSE; + return OPJ_TRUE; + } + } - if(cstr_info) { - cstr_info->codestream_size = cio_tell(cio) + j2k->pos_correction; - /* UniPG>> */ - /* The following adjustment is done to adjust the codestream size */ - /* if SOD is not at 0 in the buffer. Useful in case of JP2, where */ - /* the first bunch of bytes is not in the codestream */ - cstr_info->codestream_size -= cstr_info->main_head_start; - /* <m_tcd, p_j2k->m_current_tile_number)) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Cannot decode tile, memory error\n"); + return OPJ_FALSE; } -#ifdef USE_JPWL - /* - preparation of JPWL marker segments - */ - if(cp->epc_on) { + opj_event_msg_v2(p_manager, EVT_INFO, "Header of tile %d / %d has been read.\n", + p_j2k->m_current_tile_number, (p_j2k->m_cp.th * p_j2k->m_cp.tw) - 1); - /* encode according to JPWL */ - jpwl_encode(j2k, cio, image); + *p_tile_index = p_j2k->m_current_tile_number; + *p_go_on = OPJ_TRUE; + *p_data_size = tcd_get_decoded_tile_size(p_j2k->m_tcd); + *p_tile_x0 = p_j2k->m_tcd->tcd_image->tiles->x0; + *p_tile_y0 = p_j2k->m_tcd->tcd_image->tiles->y0; + *p_tile_x1 = p_j2k->m_tcd->tcd_image->tiles->x1; + *p_tile_y1 = p_j2k->m_tcd->tcd_image->tiles->y1; + *p_nb_comps = p_j2k->m_tcd->tcd_image->tiles->numcomps; - } -#endif /* USE_JPWL */ + p_j2k->m_specific_param.m_decoder.m_state |= 0x0080;/* FIXME J2K_DEC_STATE_DATA;*/ return OPJ_TRUE; } -static void j2k_add_mhmarker(opj_codestream_info_t *cstr_info, unsigned short int type, int pos, int len) { - if (!cstr_info) - return; +opj_bool j2k_decode_tile ( opj_j2k_v2_t * p_j2k, + OPJ_UINT32 p_tile_index, + OPJ_BYTE * p_data, + OPJ_UINT32 p_data_size, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ) +{ + OPJ_UINT32 l_current_marker; + OPJ_BYTE l_data [2]; + opj_tcp_v2_t * l_tcp; - /* expand the list? */ - if ((cstr_info->marknum + 1) > cstr_info->maxmarknum) { - cstr_info->maxmarknum = 100 + (int) ((float) cstr_info->maxmarknum * 1.0F); - cstr_info->marker = (opj_marker_info_t*)opj_realloc(cstr_info->marker, cstr_info->maxmarknum); + /* preconditions */ + assert(p_stream != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + if ( !(p_j2k->m_specific_param.m_decoder.m_state & 0x0080/*FIXME J2K_DEC_STATE_DATA*/) + || (p_tile_index != p_j2k->m_current_tile_number) ) { + return OPJ_FALSE; } - /* add the marker */ - cstr_info->marker[cstr_info->marknum].type = type; - cstr_info->marker[cstr_info->marknum].pos = pos; - cstr_info->marker[cstr_info->marknum].len = len; - cstr_info->marknum++; + l_tcp = &(p_j2k->m_cp.tcps[p_tile_index]); + if (! l_tcp->m_data) { + j2k_tcp_destroy(l_tcp); + return OPJ_FALSE; + } -} + if (! tcd_decode_tile_v2( p_j2k->m_tcd, + l_tcp->m_data, + l_tcp->m_data_size, + p_tile_index, + p_j2k->cstr_index) ) { + j2k_tcp_destroy(l_tcp); + p_j2k->m_specific_param.m_decoder.m_state |= 0x8000;/*FIXME J2K_DEC_STATE_ERR;*/ + return OPJ_FALSE; + } + + if (! tcd_update_tile_data(p_j2k->m_tcd,p_data,p_data_size)) { + return OPJ_FALSE; + } -static void j2k_add_mhmarker_v2(opj_codestream_index_t *cstr_index, OPJ_UINT32 type, OPJ_OFF_T pos, OPJ_UINT32 len) { + /* To avoid to destroy the tcp which can be useful when we try to decode a tile decoded before (cf j2k_random_tile_access) + * we destroy just the data which will be re-read in read_tile_header*/ + /*j2k_tcp_destroy(l_tcp); + p_j2k->m_tcd->tcp = 0;*/ + j2k_tcp_data_destroy(l_tcp); - if (!cstr_index) - return; + p_j2k->m_specific_param.m_decoder.m_can_decode = 0; + p_j2k->m_specific_param.m_decoder.m_state &= (~ (0x0080));/* FIXME J2K_DEC_STATE_DATA);*/ - /* expand the list? */ - if ((cstr_index->marknum + 1) > cstr_index->maxmarknum) { - cstr_index->maxmarknum = 100 + (int) ((float) cstr_index->maxmarknum * 1.0F); - cstr_index->marker = (opj_marker_info_t*)opj_realloc(cstr_index->marker, cstr_index->maxmarknum *sizeof(opj_marker_info_t)); + if (p_j2k->m_specific_param.m_decoder.m_state != 0x0100){ /*FIXME J2K_DEC_STATE_EOC)*/ + if (opj_stream_read_data(p_stream,l_data,2,p_manager) != 2) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Stream too short\n"); + return OPJ_FALSE; + } + + opj_read_bytes(l_data,&l_current_marker,2); + + if (l_current_marker == J2K_MS_EOC) { + p_j2k->m_current_tile_number = 0; + p_j2k->m_specific_param.m_decoder.m_state = 0x0100;/*FIXME J2K_DEC_STATE_EOC;*/ + } + else if (l_current_marker != J2K_MS_SOT) + { + opj_event_msg_v2(p_manager, EVT_ERROR, "Stream too short, expected SOT\n"); + return OPJ_FALSE; + } } - /* add the marker */ - cstr_index->marker[cstr_index->marknum].type = (OPJ_UINT16)type; - cstr_index->marker[cstr_index->marknum].pos = (OPJ_INT32)pos; - cstr_index->marker[cstr_index->marknum].len = (OPJ_INT32)len; - cstr_index->marknum++; + return OPJ_TRUE; +} + + +opj_bool j2k_update_image_data (opj_tcd_v2_t * p_tcd, OPJ_BYTE * p_data, opj_image_t* p_output_image) +{ + OPJ_UINT32 i,j,k = 0; + 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_INT32 l_start_offset_src, l_line_offset_src, l_end_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_INT32 l_start_offset_dest, l_line_offset_dest; + + opj_image_comp_t * l_img_comp_src = 00; + opj_image_comp_t * l_img_comp_dest = 00; -} + opj_tcd_tilecomp_v2_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_v2_t* l_res= 00; -static void j2k_add_tlmarker( int tileno, opj_codestream_info_t *cstr_info, unsigned short int type, int pos, int len) { + l_tilec = p_tcd->tcd_image->tiles->comps; + l_image_src = p_tcd->image; + l_img_comp_src = l_image_src->comps; + l_img_comp_dest = p_output_image->comps; - opj_marker_info_t *marker; + for (i=0; inumcomps; i++) { - if (!cstr_info) - return; + /* Allocate output component buffer if necessary */ + if (!l_img_comp_dest->data) { - /* expand the list? */ - if ((cstr_info->tile[tileno].marknum + 1) > cstr_info->tile[tileno].maxmarknum) { - cstr_info->tile[tileno].maxmarknum = 100 + (int) ((float) cstr_info->tile[tileno].maxmarknum * 1.0F); - cstr_info->tile[tileno].marker = (opj_marker_info_t*)opj_realloc(cstr_info->tile[tileno].marker, cstr_info->maxmarknum); - } + l_img_comp_dest->data = (OPJ_INT32*) opj_calloc(l_img_comp_dest->w * l_img_comp_dest->h, sizeof(OPJ_INT32)); + if (! l_img_comp_dest->data) { + return OPJ_FALSE; + } + } - marker = &(cstr_info->tile[tileno].marker[cstr_info->tile[tileno].marknum]); + /* Copy info from decoded comp image to output image */ + l_img_comp_dest->resno_decoded = l_img_comp_src->resno_decoded; - /* add the marker */ - marker->type = type; - marker->pos = pos; - marker->len = len; - cstr_info->tile[tileno].marknum++; -} + /*-----*/ + /* 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; -static void j2k_add_tlmarker_v2(OPJ_UINT32 tileno, opj_codestream_index_t *cstr_index, OPJ_UINT32 type, OPJ_OFF_T pos, OPJ_UINT32 len) -{ + if (l_remaining) { + ++l_size_comp; + } - if (!cstr_index) - return; + if (l_size_comp == 3) { + l_size_comp = 4; + } + /*-----*/ - if (!cstr_index->tile_index) + /* 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); + }*/ - /* expand the list? */ - if ((cstr_index->tile_index[tileno].marknum + 1) > cstr_index->tile_index[tileno].maxmarknum) { - cstr_index->tile_index[tileno].maxmarknum = 100 + (int) ((float) cstr_index->tile_index[tileno].maxmarknum * 1.0F); - cstr_index->tile_index[tileno].marker = - (opj_marker_info_t*)opj_realloc(cstr_index->tile_index[tileno].marker, - cstr_index->tile_index[tileno].maxmarknum *sizeof(opj_marker_info_t)); - } + l_width_src = (l_res->x1 - l_res->x0); + l_height_src = (l_res->y1 - l_res->y0); - /* add the marker */ - cstr_index->tile_index[tileno].marker[cstr_index->tile_index[tileno].marknum].type = (OPJ_UINT16)type; - cstr_index->tile_index[tileno].marker[cstr_index->tile_index[tileno].marknum].pos = (OPJ_INT32)pos; - cstr_index->tile_index[tileno].marker[cstr_index->tile_index[tileno].marknum].len = (OPJ_INT32)len; - cstr_index->tile_index[tileno].marknum++; + /* Border of the current output component*/ + l_x0_dest = int_ceildivpow2(l_img_comp_dest->x0, l_img_comp_dest->factor); + l_y0_dest = int_ceildivpow2(l_img_comp_dest->y0, l_img_comp_dest->factor); + l_x1_dest = l_x0_dest + l_img_comp_dest->w; + l_y1_dest = l_y0_dest + l_img_comp_dest->h; - if (type == J2K_MS_SOT) { - OPJ_UINT32 l_current_tile_part = cstr_index->tile_index[tileno].current_tpsno; + /*if (i == 0) { + fprintf(stdout, "DEST: l_x0_dest=%d, l_x1_dest=%d, l_y0_dest=%d, l_y1_dest=%d (%d)\n", + l_x0_dest, l_x1_dest, l_y0_dest, l_y1_dest, l_img_comp_dest->factor ); + }*/ - if (cstr_index->tile_index[tileno].tp_index) - cstr_index->tile_index[tileno].tp_index[l_current_tile_part].start_pos = pos; + /*-----*/ + /* Compute the area (l_offset_x0_src, l_offset_y0_src, l_offset_x1_src, l_offset_y1_src) + * of the input buffer (decoded tile component) which will be move + * in the output buffer. Compute the area of the output buffer (l_start_x_dest, + * 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 = l_res->x0 - l_x0_dest; + l_offset_x0_src = 0; - } + if ( l_x1_dest >= (OPJ_UINT32)l_res->x1 ) { + l_width_dest = l_width_src; + l_offset_x1_src = 0; + } + else { + l_width_dest = l_x1_dest - l_res->x0 ; + l_offset_x1_src = l_width_src - l_width_dest; + } + } + else { + l_start_x_dest = 0 ; + l_offset_x0_src = l_x0_dest - l_res->x0; -} + if ( l_x1_dest >= (OPJ_UINT32)l_res->x1 ) { + l_width_dest = l_width_src - 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 - l_x1_dest; + } + } + if ( l_y0_dest < (OPJ_UINT32)l_res->y0 ) { + l_start_y_dest = l_res->y0 - l_y0_dest; + l_offset_y0_src = 0; + if ( l_y1_dest >= (OPJ_UINT32)l_res->y1 ) { + l_height_dest = l_height_src; + l_offset_y1_src = 0; + } + else { + l_height_dest = l_y1_dest - l_res->y0 ; + l_offset_y1_src = l_height_src - l_height_dest; + } + } + else { + l_start_y_dest = 0 ; + l_offset_y0_src = l_y0_dest - l_res->y0; + if ( l_y1_dest >= (OPJ_UINT32)l_res->y1 ) { + l_height_dest = l_height_src - 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 - l_y1_dest; + } + } -/* - * ----------------------------------------------------------------------- - * ----------------------------------------------------------------------- - * ----------------------------------------------------------------------- - */ + if( (l_offset_x0_src < 0 ) || (l_offset_y0_src < 0 ) || (l_offset_x1_src < 0 ) || (l_offset_y1_src < 0 ) ){ + return OPJ_FALSE; + } + /*-----*/ -/** - * Ends the decompression procedures and possibiliy add data to be read after the - * codestream. - */ -opj_bool j2k_end_decompress( - opj_j2k_v2_t *p_j2k, - opj_stream_private_t *p_stream, - opj_event_mgr_t * p_manager) -{ - return OPJ_TRUE; -} + /* Compute the input buffer offset */ + l_start_offset_src = l_offset_x0_src + l_offset_y0_src * l_width_src; + l_line_offset_src = l_offset_x1_src + l_offset_x0_src; + l_end_offset_src = l_offset_y1_src * l_width_src - l_offset_x0_src; -/** - * Reads a jpeg2000 codestream header structure. + /* Compute the output buffer offset */ + l_start_offset_dest = l_start_x_dest + l_start_y_dest * l_img_comp_dest->w; + l_line_offset_dest = l_img_comp_dest->w - l_width_dest; - * - * @param p_stream the stream to read data from. - * @param p_j2k the jpeg2000 codec. - * @param p_manager the user event manager. - * - * @return true if the box is valid. - */ -opj_bool j2k_read_header( struct opj_stream_private *p_stream, - opj_j2k_v2_t* p_j2k, - opj_image_t** p_image, - struct opj_event_mgr* p_manager ) -{ - /* preconditions */ - assert(p_j2k != 00); - assert(p_stream != 00); - assert(p_manager != 00); + /* Move the output buffer to the first place where we will write*/ + l_dest_ptr = l_img_comp_dest->data + l_start_offset_dest; - /* create an empty image header */ - p_j2k->m_private_image = opj_image_create0(); - if (! p_j2k->m_private_image) { - return OPJ_FALSE; - } + /*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); - /* customization of the validation */ - j2k_setup_decoding_validation(p_j2k); + 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); + }*/ - /* validation of the parameters codec */ - if (! j2k_exec(p_j2k, p_j2k->m_validation_list, p_stream,p_manager)) { - opj_image_destroy(p_j2k->m_private_image); - p_j2k->m_private_image = NULL; - return OPJ_FALSE; - } - /* customization of the encoding */ - j2k_setup_header_reading(p_j2k); + 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*/ - /* read header */ - if (! j2k_exec (p_j2k,p_j2k->m_procedure_list,p_stream,p_manager)) { - opj_image_destroy(p_j2k->m_private_image); - p_j2k->m_private_image = NULL; - return OPJ_FALSE; - } + 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 */ + } - *p_image = opj_image_create0(); - if (! (*p_image)) { - return OPJ_FALSE; - } + 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 */ + } + } + 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); + } - /* Copy codestream image information to the output image */ - opj_copy_image_header(p_j2k->m_private_image, *p_image); + l_dest_ptr+= l_line_offset_dest; + l_src_ptr += l_line_offset_src; + } + } + 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 */ + } + break; + case 2: + { + OPJ_INT16 * l_src_ptr = (OPJ_INT16 *) p_data; + l_src_ptr += l_start_offset_src; - return OPJ_TRUE; -} + if (l_img_comp_src->sgnd) { + for (j=0;jm_procedure_list,(void*)j2k_read_header_procedure); + l_dest_ptr+= l_line_offset_dest; + l_src_ptr += l_line_offset_src ; + } + } - /* DEVELOPER CORNER, add your custom procedures */ - opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_copy_default_tcp_and_create_tcd); + 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; + l_src_ptr += l_start_offset_src; -} + for (j=0;jm_validation_list, (void*)j2k_build_decoder); - opj_procedure_list_add_procedure(p_j2k->m_validation_list, (void*)j2k_decoding_validation); - /* DEVELOPER CORNER, add your custom validation procedure */ + 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; + } -/** - * Builds the cp decoder parameters to use to decode tile. - */ -opj_bool j2k_build_decoder ( - opj_j2k_v2_t * p_j2k, - opj_stream_private_t *p_stream, - opj_event_mgr_t * p_manager - ) -{ - // add here initialization of cp - // copy paste of setup_decoder return OPJ_TRUE; } /** - * The default decoding validation procedure without any extension. + * Sets the given area to be decoded. This function should be called right after opj_read_header and before any tile header reading. * - * @param p_j2k the jpeg2000 codec to validate. - * @param p_stream the input stream to validate. - * @param p_manager the user event manager. + * @param p_j2k the jpeg2000 codec. + * @param p_start_x the left position of the rectangle to decode (in image coordinates). + * @param p_end_x the right position of the rectangle to decode (in image coordinates). + * @param p_start_y the up position of the rectangle to decode (in image coordinates). + * @param p_end_y the bottom position of the rectangle to decode (in image coordinates). + * @param p_manager the user event manager * - * @return true if the parameters are correct. + * @return true if the area could be set. */ -opj_bool j2k_decoding_validation ( - opj_j2k_v2_t *p_j2k, - opj_stream_private_t *p_stream, - opj_event_mgr_t * p_manager - ) +opj_bool j2k_set_decode_area( opj_j2k_v2_t *p_j2k, + opj_image_t* p_image, + OPJ_INT32 p_start_x, OPJ_INT32 p_start_y, + OPJ_INT32 p_end_x, OPJ_INT32 p_end_y, + struct opj_event_mgr * p_manager ) { - opj_bool l_is_valid = OPJ_TRUE; - - // preconditions - assert(p_j2k != 00); - assert(p_stream != 00); - assert(p_manager != 00); + opj_cp_v2_t * l_cp = &(p_j2k->m_cp); + opj_image_t * l_image = p_j2k->m_private_image; + OPJ_UINT32 it_comp; + OPJ_INT32 l_comp_x1, l_comp_y1; + opj_image_comp_t* l_img_comp = NULL; - /* STATE checking */ - /* make sure the state is at 0 */ -#ifdef TODO_MSD - l_is_valid &= (p_j2k->m_specific_param.m_decoder.m_state == J2K_DEC_STATE_NONE); -#endif - l_is_valid &= (p_j2k->m_specific_param.m_decoder.m_state == 0x0000); + /* Check if we are read the main header */ + if (p_j2k->m_specific_param.m_decoder.m_state != J2K_STATE_TPHSOT) { /* FIXME J2K_DEC_STATE_TPHSOT)*/ + opj_event_msg_v2(p_manager, EVT_ERROR, "Need to decode the main header before begin to decode the remaining codestream"); + return OPJ_FALSE; + } - /* POINTER validation */ - /* make sure a p_j2k codec is present */ - /* make sure a procedure list is present */ - l_is_valid &= (p_j2k->m_procedure_list != 00); - /* make sure a validation list is present */ - l_is_valid &= (p_j2k->m_validation_list != 00); + if ( !p_start_x && !p_start_y && !p_end_x && !p_end_y){ + opj_event_msg_v2(p_manager, EVT_INFO, "No decoded area parameters, set the decoded area to the whole image\n"); - /* PARAMETER VALIDATION */ - return l_is_valid; -} + p_j2k->m_specific_param.m_decoder.m_start_tile_x = 0; + p_j2k->m_specific_param.m_decoder.m_start_tile_y = 0; + p_j2k->m_specific_param.m_decoder.m_end_tile_x = l_cp->tw; + p_j2k->m_specific_param.m_decoder.m_end_tile_y = l_cp->th; -opj_bool j2k_read_header_procedure( opj_j2k_v2_t *p_j2k, - struct opj_stream_private *p_stream, - struct opj_event_mgr * p_manager) -{ - OPJ_UINT32 l_current_marker; - OPJ_UINT32 l_marker_size; - const opj_dec_memory_marker_handler_t * l_marker_handler = 00; + return OPJ_TRUE; + } - /* preconditions */ - assert(p_stream != 00); - assert(p_j2k != 00); - assert(p_manager != 00); + /* ----- */ + /* Check if the positions provided by the user are correct */ - /* We enter in the main header */ - p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_MHSOC; + /* Left */ + assert(p_start_x >= 0 ); + assert(p_start_y >= 0 ); - /* Try to read the SOC marker, the codestream must begin with SOC marker */ - if (! j2k_read_soc_v2(p_j2k,p_stream,p_manager)) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Expected a SOC marker \n"); + if ((OPJ_UINT32)p_start_x > l_image->x1 ) { + opj_event_msg_v2(p_manager, EVT_ERROR, + "Left position of the decoded area (region_x0=%d) is outside the image area (Xsiz=%d).\n", + p_start_x, l_image->x1); return OPJ_FALSE; } + else if ((OPJ_UINT32)p_start_x < l_image->x0){ + opj_event_msg_v2(p_manager, EVT_WARNING, + "Left position of the decoded area (region_x0=%d) is outside the image area (XOsiz=%d).\n", + p_start_x, l_image->x0); + p_j2k->m_specific_param.m_decoder.m_start_tile_x = 0; + p_image->x0 = l_image->x0; + } + else { + p_j2k->m_specific_param.m_decoder.m_start_tile_x = (p_start_x - l_cp->tx0) / l_cp->tdx; + p_image->x0 = p_start_x; + } - /* 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_v2(p_manager, EVT_ERROR, "Stream too short\n"); + /* Up */ + if ((OPJ_UINT32)p_start_y > l_image->y1){ + opj_event_msg_v2(p_manager, EVT_ERROR, + "Up position of the decoded area (region_y0=%d) is outside the image area (Ysiz=%d).\n", + p_start_y, l_image->y1); return OPJ_FALSE; } + else if ((OPJ_UINT32)p_start_y < l_image->y0){ + opj_event_msg_v2(p_manager, EVT_WARNING, + "Up position of the decoded area (region_y0=%d) is outside the image area (YOsiz=%d).\n", + p_start_y, l_image->y0); + p_j2k->m_specific_param.m_decoder.m_start_tile_y = 0; + p_image->y0 = l_image->y0; + } + else { + p_j2k->m_specific_param.m_decoder.m_start_tile_y = (p_start_y - l_cp->ty0) / l_cp->tdy; + p_image->y0 = p_start_y; + } - /* Read 2 bytes as the new marker ID */ - opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data,&l_current_marker,2); - - /* Try to read until the SOT is detected */ - while (l_current_marker != J2K_MS_SOT) { - - /* Check if the current marker ID is valid */ - if (l_current_marker < 0xff00) { - opj_event_msg_v2(p_manager, EVT_ERROR, "We expected read a marker ID (0xff--) instead of %.8x\n", l_current_marker); - return OPJ_FALSE; - } - - /* Get the marker handler from the marker ID */ - l_marker_handler = j2k_get_marker_handler(l_current_marker); - - /* Manage case where marker is unknown */ - if (l_marker_handler->id == J2K_MS_UNK) { - if (! j2k_read_unk_v2(p_j2k, p_stream, &l_current_marker, p_manager)){ - opj_event_msg_v2(p_manager, EVT_ERROR, "Unknow marker have been detected and generated error.\n"); - return OPJ_FALSE; - } - - if (l_current_marker == J2K_MS_SOT) - break; /* SOT marker is detected main header is completely read */ - else /* Get the marker handler from the marker ID */ - l_marker_handler = j2k_get_marker_handler(l_current_marker); - } - - /* Check if the marker is known and if it is the right place to find it */ - if (! (p_j2k->m_specific_param.m_decoder.m_state & l_marker_handler->states) ) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Marker is not compliant with its position\n"); - return OPJ_FALSE; - } + /* Right */ + assert((OPJ_UINT32)p_end_x > 0); + assert((OPJ_UINT32)p_end_y > 0); + if ((OPJ_UINT32)p_end_x < l_image->x0) { + opj_event_msg_v2(p_manager, EVT_ERROR, + "Right position of the decoded area (region_x1=%d) is outside the image area (XOsiz=%d).\n", + p_end_x, l_image->x0); + return OPJ_FALSE; + } + else if ((OPJ_UINT32)p_end_x > l_image->x1) { + opj_event_msg_v2(p_manager, EVT_WARNING, + "Right position of the decoded area (region_x1=%d) is outside the image area (Xsiz=%d).\n", + p_end_x, l_image->x1); + p_j2k->m_specific_param.m_decoder.m_end_tile_x = l_cp->tw; + p_image->x1 = l_image->x1; + } + else { + p_j2k->m_specific_param.m_decoder.m_end_tile_x = int_ceildiv((p_end_x - l_cp->tx0), l_cp->tdx); + p_image->x1 = p_end_x; + } - /* Try to read 2 bytes (the marker size) 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_v2(p_manager, EVT_ERROR, "Stream too short\n"); - return OPJ_FALSE; - } + /* Bottom */ + if ((OPJ_UINT32)p_end_y < l_image->y0) { + opj_event_msg_v2(p_manager, EVT_ERROR, + "Bottom position of the decoded area (region_y1=%d) is outside the image area (YOsiz=%d).\n", + p_end_y, l_image->y0); + return OPJ_FALSE; + } + if ((OPJ_UINT32)p_end_y > l_image->y1){ + opj_event_msg_v2(p_manager, EVT_WARNING, + "Bottom position of the decoded area (region_y1=%d) is outside the image area (Ysiz=%d).\n", + p_end_y, l_image->y1); + p_j2k->m_specific_param.m_decoder.m_end_tile_y = l_cp->th; + p_image->y1 = l_image->y1; + } + else{ + p_j2k->m_specific_param.m_decoder.m_end_tile_y = int_ceildiv((p_end_y - l_cp->ty0), l_cp->tdy); + p_image->y1 = p_end_y; + } + /* ----- */ - /* read 2 bytes as the marker size */ - opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data,&l_marker_size,2); - l_marker_size -= 2; // Subtract the size of the marker ID already read + p_j2k->m_specific_param.m_decoder.m_discard_tiles = 1; - /* Check if the marker size is compatible with the header data size */ - if (l_marker_size > p_j2k->m_specific_param.m_decoder.m_header_data_size) { - p_j2k->m_specific_param.m_decoder.m_header_data = (OPJ_BYTE*) - opj_realloc(p_j2k->m_specific_param.m_decoder.m_header_data,l_marker_size); - if (p_j2k->m_specific_param.m_decoder.m_header_data == 00) { - return OPJ_FALSE; - } - p_j2k->m_specific_param.m_decoder.m_header_data_size = l_marker_size; - } + l_img_comp = p_image->comps; + for (it_comp=0; it_comp < p_image->numcomps; ++it_comp) + { + OPJ_INT32 l_h,l_w; - /* Try to read the rest of the marker segment 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,l_marker_size,p_manager) != l_marker_size) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Stream too short\n"); - return OPJ_FALSE; - } + l_img_comp->x0 = int_ceildiv(p_image->x0, l_img_comp->dx); + l_img_comp->y0 = int_ceildiv(p_image->y0, l_img_comp->dy); + l_comp_x1 = int_ceildiv(p_image->x1, l_img_comp->dx); + l_comp_y1 = int_ceildiv(p_image->y1, l_img_comp->dy); - /* Read the marker segment with the correct marker handler */ - if (! (*(l_marker_handler->handler))(p_j2k,p_j2k->m_specific_param.m_decoder.m_header_data,l_marker_size,p_manager)) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Marker handler function failed to read the marker segment\n"); + l_w = int_ceildivpow2(l_comp_x1, l_img_comp->factor) + - int_ceildivpow2(l_img_comp->x0, l_img_comp->factor); + if (l_w < 0){ + opj_event_msg_v2(p_manager, EVT_ERROR, + "Size x of the decoded component image is incorrect (comp[%d].w=%d).\n", + it_comp, l_w); return OPJ_FALSE; } + l_img_comp->w = l_w; - /* Add the marker to the codestream index*/ - j2k_add_mhmarker_v2(p_j2k->cstr_index, - l_marker_handler->id, - (OPJ_UINT32) opj_stream_tell(p_stream) - l_marker_size - 4, - l_marker_size + 4 ); - - /* 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_v2(p_manager, EVT_ERROR, "Stream too short\n"); + l_h = int_ceildivpow2(l_comp_y1, l_img_comp->factor) + - int_ceildivpow2(l_img_comp->y0, l_img_comp->factor); + if (l_h < 0){ + opj_event_msg_v2(p_manager, EVT_ERROR, + "Size y of the decoded component image is incorrect (comp[%d].h=%d).\n", + it_comp, l_h); return OPJ_FALSE; } + l_img_comp->h = l_h; - /* read 2 bytes as the new marker ID */ - opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data,&l_current_marker,2); + l_img_comp++; } - opj_event_msg_v2(p_manager, EVT_INFO, "Main header has been correctly decode.\n"); - - /* Position of the last element if the main header */ - p_j2k->cstr_index->main_head_end = (OPJ_UINT32) opj_stream_tell(p_stream) - 2; + opj_event_msg_v2( p_manager, EVT_INFO,"Setting decoding area to %d,%d,%d,%d\n", + p_image->x0, p_image->y0, p_image->x1, p_image->y1); - /* Next step: read a tile-part header */ - p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_TPHSOT; return OPJ_TRUE; } + +/* ----------------------------------------------------------------------- */ +/* J2K / JPT decoder interface */ +/* ----------------------------------------------------------------------- */ /** - * Excutes 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. - * @param p_stream the stream to execute the procedures on. - * @param p_manager the user manager. + * Creates a J2K decompression structure. * - * @return true if all the procedures were successfully executed. - */ -opj_bool j2k_exec ( opj_j2k_v2_t * p_j2k, - opj_procedure_list_t * p_procedure_list, - opj_stream_private_t *p_stream, - opj_event_mgr_t * p_manager ) + * @return a handle to a J2K decompressor if successful, NULL otherwise. +*/ +opj_j2k_v2_t* opj_j2k_create_decompress(void) { - opj_bool (** l_procedure) (opj_j2k_v2_t * ,opj_stream_private_t *,opj_event_mgr_t *) = 00; - opj_bool l_result = OPJ_TRUE; - OPJ_UINT32 l_nb_proc, i; - - // preconditions - assert(p_procedure_list != 00); - assert(p_j2k != 00); - assert(p_stream != 00); - assert(p_manager != 00); - - - l_nb_proc = opj_procedure_list_get_nb_procedures(p_procedure_list); - l_procedure = (opj_bool (**) (opj_j2k_v2_t * ,opj_stream_private_t *,opj_event_mgr_t *)) opj_procedure_list_get_first_procedure(p_procedure_list); - - for (i=0;im_private_image; - l_nb_tiles = p_j2k->m_cp.th * p_j2k->m_cp.tw; - l_tcp = p_j2k->m_cp.tcps; - l_tccp_size = l_image->numcomps * sizeof(opj_tccp_t); - l_default_tcp = p_j2k->m_specific_param.m_decoder.m_default_tcp; - l_mct_size = l_image->numcomps * l_image->numcomps * sizeof(OPJ_FLOAT32); - - /* For each tile */ - for (i=0; itccps; - /*Copy default coding parameters into the current tile coding parameters*/ - memcpy(l_tcp, l_default_tcp, sizeof(opj_tcp_v2_t)); - /* Initialize some values of the current tile coding parameters*/ - l_tcp->ppt = 0; - l_tcp->ppt_data = 00; - /* Reconnect the tile-compo coding parameters pointer to the current tile coding parameters*/ - l_tcp->tccps = l_current_tccp; - - /* Get the mct_decoding_matrix of the dflt_tile_cp and copy them into the current tile cp*/ - if (l_default_tcp->m_mct_decoding_matrix) { - l_tcp->m_mct_decoding_matrix = (OPJ_FLOAT32*)opj_malloc(l_mct_size); - if (! l_tcp->m_mct_decoding_matrix ) { - return OPJ_FALSE; - } - memcpy(l_tcp->m_mct_decoding_matrix,l_default_tcp->m_mct_decoding_matrix,l_mct_size); - } - - /* Get the mct_record of the dflt_tile_cp and copy them into the current tile cp*/ - l_mct_records_size = l_default_tcp->m_nb_max_mct_records * sizeof(opj_mct_data_t); - l_tcp->m_mct_records = (opj_mct_data_t*)opj_malloc(l_mct_records_size); - if (! l_tcp->m_mct_records) { - return OPJ_FALSE; - } - memcpy(l_tcp->m_mct_records, l_default_tcp->m_mct_records,l_mct_records_size); - - /* Copy the mct record data from dflt_tile_cp to the current tile*/ - l_src_mct_rec = l_default_tcp->m_mct_records; - l_dest_mct_rec = l_tcp->m_mct_records; - - for (j=0;jm_nb_mct_records;++j) { - - if (l_src_mct_rec->m_data) { - - l_dest_mct_rec->m_data = (OPJ_BYTE*) opj_malloc(l_src_mct_rec->m_data_size); - if(! l_dest_mct_rec->m_data) { - return OPJ_FALSE; - } - memcpy(l_dest_mct_rec->m_data,l_src_mct_rec->m_data,l_src_mct_rec->m_data_size); - } - - ++l_src_mct_rec; - ++l_dest_mct_rec; - } - - /* Get the mcc_record of the dflt_tile_cp and copy them into the current tile cp*/ - l_mcc_records_size = l_default_tcp->m_nb_max_mcc_records * sizeof(opj_simple_mcc_decorrelation_data_t); - l_tcp->m_mcc_records = (opj_simple_mcc_decorrelation_data_t*) opj_malloc(l_mcc_records_size); - if (! l_tcp->m_mcc_records) { - return OPJ_FALSE; - } - memcpy(l_tcp->m_mcc_records,l_default_tcp->m_mcc_records,l_mcc_records_size); + l_j2k->m_is_decoder = 1; + l_j2k->m_cp.m_is_decoder = 1; - /* Copy the mcc record data from dflt_tile_cp to the current tile*/ - l_src_mcc_rec = l_default_tcp->m_mcc_records; - l_dest_mcc_rec = l_tcp->m_mcc_records; + l_j2k->m_specific_param.m_decoder.m_default_tcp = (opj_tcp_v2_t*) opj_malloc(sizeof(opj_tcp_v2_t)); + if (!l_j2k->m_specific_param.m_decoder.m_default_tcp) { + j2k_destroy(l_j2k); + return 00; + } + memset(l_j2k->m_specific_param.m_decoder.m_default_tcp,0,sizeof(opj_tcp_v2_t)); - for (j=0;jm_nb_max_mcc_records;++j) { + l_j2k->m_specific_param.m_decoder.m_header_data = (OPJ_BYTE *) opj_malloc(J2K_DEFAULT_HEADER_SIZE); + if (! l_j2k->m_specific_param.m_decoder.m_header_data) { + j2k_destroy(l_j2k); + return 00; + } - if (l_src_mcc_rec->m_decorrelation_array) { - l_offset = l_src_mcc_rec->m_decorrelation_array - l_default_tcp->m_mct_records; - l_dest_mcc_rec->m_decorrelation_array = l_tcp->m_mct_records + l_offset; - } + l_j2k->m_specific_param.m_decoder.m_header_data_size = J2K_DEFAULT_HEADER_SIZE; - if (l_src_mcc_rec->m_offset_array) { - l_offset = l_src_mcc_rec->m_offset_array - l_default_tcp->m_mct_records; - l_dest_mcc_rec->m_offset_array = l_tcp->m_mct_records + l_offset; - } + l_j2k->m_specific_param.m_decoder.m_tile_ind_to_dec = -1 ; - ++l_src_mcc_rec; - ++l_dest_mcc_rec; - } + l_j2k->m_specific_param.m_decoder.m_last_sot_read_pos = 0 ; - /* Copy all the dflt_tile_compo_cp to the current tile cp */ - memcpy(l_current_tccp,l_default_tcp->tccps,l_tccp_size); + /* codestream index creation */ + l_j2k->cstr_index = j2k_create_cstr_index(); - /* Move to next tile cp*/ - ++l_tcp; + /*(opj_codestream_index_t*) opj_malloc(sizeof(opj_codestream_index_t)); + if (!l_j2k->cstr_index){ + j2k_destroy(l_j2k); + return NULL; } - /* Create the current tile decoder*/ - p_j2k->m_tcd = (opj_tcd_v2_t*)tcd_create_v2(OPJ_TRUE); // FIXME why a cast ? - if (! p_j2k->m_tcd ) { - return OPJ_FALSE; + l_j2k->cstr_index->marker = (opj_marker_info_t*) opj_malloc(100 * sizeof(opj_marker_info_t)); +*/ + + /* validation list creation */ + l_j2k->m_validation_list = opj_procedure_list_create(); + if (! l_j2k->m_validation_list) { + j2k_destroy(l_j2k); + return 00; } - if ( !tcd_init_v2(p_j2k->m_tcd, l_image, &(p_j2k->m_cp)) ) { - tcd_destroy_v2(p_j2k->m_tcd); - p_j2k->m_tcd = 00; - opj_event_msg_v2(p_manager, EVT_ERROR, "Cannot decode tile, memory error\n"); - return OPJ_FALSE; + /* execution list creation */ + l_j2k->m_procedure_list = opj_procedure_list_create(); + if (! l_j2k->m_procedure_list) { + j2k_destroy(l_j2k); + return 00; } - return OPJ_TRUE; + return l_j2k; } -/** - * Reads the lookup table containing all the marker, status and action, and returns the handler associated - * with the marker value. - * @param p_id Marker value to look up - * - * @return the handler associated with the id. -*/ -const opj_dec_memory_marker_handler_t * j2k_get_marker_handler (OPJ_UINT32 p_id) + +opj_codestream_index_t* j2k_create_cstr_index(void) { - const opj_dec_memory_marker_handler_t *e; - for (e = j2k_memory_marker_handler_tab; e->id != 0; ++e) { - if (e->id == p_id) { - break; // we find a handler corresponding to the marker ID - } - } - return e; + opj_codestream_index_t* cstr_index = (opj_codestream_index_t*) + opj_calloc(1,sizeof(opj_codestream_index_t)); + if (!cstr_index) + return NULL; + + cstr_index->maxmarknum = 100; + cstr_index->marknum = 0; + cstr_index->marker = (opj_marker_info_t*) + opj_calloc(cstr_index->maxmarknum, sizeof(opj_marker_info_t)); + if (!cstr_index-> marker) + return NULL; + + cstr_index->tile_index = NULL; + + return cstr_index; } /** - * Destroys a jpeg2000 codec. + * Gets the size taken by writing a SPCod or SPCoc for the given tile and component. * - * @param p_j2k the jpeg20000 structure to destroy. + * @param p_tile_no the tile index. + * @param p_comp_no the component being outputted. + * @param p_j2k the J2K codec. + * + * @return the number of bytes taken by the SPCod element. */ -void j2k_destroy (opj_j2k_v2_t *p_j2k) +OPJ_UINT32 j2k_get_SPCod_SPCoc_size ( opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no ) { - if (p_j2k == 00) { - return; - } + opj_cp_v2_t *l_cp = 00; + opj_tcp_v2_t *l_tcp = 00; + opj_tccp_t *l_tccp = 00; - if (p_j2k->m_is_decoder) { + /* preconditions */ + assert(p_j2k != 00); - if (p_j2k->m_specific_param.m_decoder.m_default_tcp != 00) { - j2k_tcp_destroy(p_j2k->m_specific_param.m_decoder.m_default_tcp); - opj_free(p_j2k->m_specific_param.m_decoder.m_default_tcp); - p_j2k->m_specific_param.m_decoder.m_default_tcp = 00; - } + l_cp = &(p_j2k->m_cp); + l_tcp = &l_cp->tcps[p_tile_no]; + l_tccp = &l_tcp->tccps[p_comp_no]; - if (p_j2k->m_specific_param.m_decoder.m_header_data != 00) { - opj_free(p_j2k->m_specific_param.m_decoder.m_header_data); - p_j2k->m_specific_param.m_decoder.m_header_data = 00; - p_j2k->m_specific_param.m_decoder.m_header_data_size = 0; - } + /* preconditions again */ + assert(p_tile_no < (l_cp->tw * l_cp->th)); + assert(p_comp_no < p_j2k->m_private_image->numcomps); + + if (l_tccp->csty & J2K_CCP_CSTY_PRT) { + return 5 + l_tccp->numresolutions; } else { + return 5; + } +} - if (p_j2k->m_specific_param.m_encoder.m_encoded_tile_data) { - opj_free(p_j2k->m_specific_param.m_encoder.m_encoded_tile_data); - p_j2k->m_specific_param.m_encoder.m_encoded_tile_data = 00; - } +/** + * Writes a SPCod or SPCoc element, i.e. the coding style of a given component of a tile. + * + * @param p_comp_no the component number to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. + * +*/ +opj_bool j2k_write_SPCod_SPCoc( opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_header_size, + struct opj_event_mgr * p_manager ) +{ + OPJ_UINT32 i; + opj_cp_v2_t *l_cp = 00; + opj_tcp_v2_t *l_tcp = 00; + opj_tccp_t *l_tccp = 00; - if (p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer) { - opj_free(p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer); - p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer = 00; - p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current = 00; - } + /* preconditions */ + assert(p_j2k != 00); + assert(p_header_size != 00); + assert(p_manager != 00); + assert(p_data != 00); - if (p_j2k->m_specific_param.m_encoder.m_header_tile_data) { - opj_free(p_j2k->m_specific_param.m_encoder.m_header_tile_data); - p_j2k->m_specific_param.m_encoder.m_header_tile_data = 00; - p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = 0; - } - } + l_cp = &(p_j2k->m_cp); + l_tcp = &l_cp->tcps[p_tile_no]; + l_tccp = &l_tcp->tccps[p_comp_no]; - tcd_destroy_v2(p_j2k->m_tcd); + /* preconditions again */ + assert(p_tile_no < (l_cp->tw * l_cp->th)); + assert(p_comp_no <(p_j2k->m_private_image->numcomps)); - j2k_cp_destroy(&(p_j2k->m_cp)); - memset(&(p_j2k->m_cp),0,sizeof(opj_cp_v2_t)); + if (*p_header_size < 5) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error writing SPCod SPCoc element\n"); + return OPJ_FALSE; + } - opj_procedure_list_destroy(p_j2k->m_procedure_list); - p_j2k->m_procedure_list = 00; + opj_write_bytes(p_data,l_tccp->numresolutions - 1, 1); /* SPcoc (D) */ + ++p_data; - opj_procedure_list_destroy(p_j2k->m_validation_list); - p_j2k->m_procedure_list = 00; + opj_write_bytes(p_data,l_tccp->cblkw - 2, 1); /* SPcoc (E) */ + ++p_data; - j2k_destroy_cstr_index(p_j2k->cstr_index); - p_j2k->cstr_index = NULL; + opj_write_bytes(p_data,l_tccp->cblkh - 2, 1); /* SPcoc (F) */ + ++p_data; - opj_image_destroy(p_j2k->m_private_image); - p_j2k->m_private_image = NULL; + opj_write_bytes(p_data,l_tccp->cblksty, 1); /* SPcoc (G) */ + ++p_data; - opj_image_destroy(p_j2k->m_output_image); - p_j2k->m_output_image = NULL; + opj_write_bytes(p_data,l_tccp->qmfbid, 1); /* SPcoc (H) */ + ++p_data; - opj_free(p_j2k); -} + *p_header_size = *p_header_size - 5; -void j2k_destroy_cstr_index (opj_codestream_index_t *p_cstr_ind) -{ - if (p_cstr_ind) { + if (l_tccp->csty & J2K_CCP_CSTY_PRT) { - if (p_cstr_ind->marker) { - opj_free(p_cstr_ind->marker); - p_cstr_ind->marker = NULL; + if (*p_header_size < l_tccp->numresolutions) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error writting SPCod SPCoc element\n"); + return OPJ_FALSE; } - if (p_cstr_ind->tile_index) { - OPJ_UINT32 it_tile = 0; - - for (it_tile=0; it_tile < p_cstr_ind->nb_of_tiles; it_tile++) { - - if(p_cstr_ind->tile_index[it_tile].packet_index) { - opj_free(p_cstr_ind->tile_index[it_tile].packet_index); - p_cstr_ind->tile_index[it_tile].packet_index = NULL; - } + for (i = 0; i < l_tccp->numresolutions; ++i) { + opj_write_bytes(p_data,l_tccp->prcw[i] + (l_tccp->prch[i] << 4), 1); /* SPcoc (I_i) */ + ++p_data; + } - if(p_cstr_ind->tile_index[it_tile].tp_index){ - opj_free(p_cstr_ind->tile_index[it_tile].tp_index); - p_cstr_ind->tile_index[it_tile].tp_index = NULL; - } + *p_header_size = *p_header_size - l_tccp->numresolutions; + } - if(p_cstr_ind->tile_index[it_tile].marker){ - opj_free(p_cstr_ind->tile_index[it_tile].marker); - p_cstr_ind->tile_index[it_tile].marker = NULL; + return OPJ_TRUE; +} - } - } +/** + * Reads a SPCod or SPCoc element, i.e. the coding style of a given component of a tile. + * @param p_header_data the data contained in the COM box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the COM marker. + * @param p_manager the user event manager. +*/ +opj_bool j2k_read_SPCod_SPCoc( + opj_j2k_v2_t *p_j2k, + OPJ_UINT32 compno, + OPJ_BYTE * p_header_data, + OPJ_UINT32 * p_header_size, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 i, l_tmp; + opj_cp_v2_t *l_cp = NULL; + opj_tcp_v2_t *l_tcp = NULL; + opj_tccp_t *l_tccp = NULL; + OPJ_BYTE * l_current_ptr = NULL; - opj_free( p_cstr_ind->tile_index); - p_cstr_ind->tile_index = NULL; - } + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_header_data != 00); - opj_free(p_cstr_ind); - } -} + l_cp = &(p_j2k->m_cp); + l_tcp = (p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_TPH) ? + &l_cp->tcps[p_j2k->m_current_tile_number] : + p_j2k->m_specific_param.m_decoder.m_default_tcp; + /* precondition again */ + assert(compno < p_j2k->m_private_image->numcomps); + l_tccp = &l_tcp->tccps[compno]; + l_current_ptr = p_header_data; -/** - * Destroys a tile coding parameter structure. - * - * @param p_tcp the tile coding parameter to destroy. - */ -void j2k_tcp_destroy (opj_tcp_v2_t *p_tcp) -{ - if (p_tcp == 00) { - return; + /* make sure room is sufficient */ + if (*p_header_size < 5) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading SPCod SPCoc element\n"); + return OPJ_FALSE; } - if (p_tcp->ppt_buffer != 00) { - opj_free(p_tcp->ppt_buffer); - p_tcp->ppt_buffer = 00; - } + opj_read_bytes(l_current_ptr, &l_tccp->numresolutions ,1); /* SPcox (D) */ + ++l_tccp->numresolutions; /* tccp->numresolutions = read() + 1 */ + ++l_current_ptr; - if (p_tcp->tccps != 00) { - opj_free(p_tcp->tccps); - p_tcp->tccps = 00; + /* 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_v2(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); + p_j2k->m_specific_param.m_decoder.m_state |= 0x8000;/* FIXME J2K_DEC_STATE_ERR;*/ + return OPJ_FALSE; } - if (p_tcp->m_mct_coding_matrix != 00) { - opj_free(p_tcp->m_mct_coding_matrix); - p_tcp->m_mct_coding_matrix = 00; - } + opj_read_bytes(l_current_ptr,&l_tccp->cblkw ,1); /* SPcoc (E) */ + ++l_current_ptr; + l_tccp->cblkw += 2; - if (p_tcp->m_mct_decoding_matrix != 00) { - opj_free(p_tcp->m_mct_decoding_matrix); - p_tcp->m_mct_decoding_matrix = 00; - } + opj_read_bytes(l_current_ptr,&l_tccp->cblkh ,1); /* SPcoc (F) */ + ++l_current_ptr; + l_tccp->cblkh += 2; - if (p_tcp->m_mcc_records) { - opj_free(p_tcp->m_mcc_records); - p_tcp->m_mcc_records = 00; - p_tcp->m_nb_max_mcc_records = 0; - p_tcp->m_nb_mcc_records = 0; - } + opj_read_bytes(l_current_ptr,&l_tccp->cblksty ,1); /* SPcoc (G) */ + ++l_current_ptr; - if (p_tcp->m_mct_records) { - opj_mct_data_t * l_mct_data = p_tcp->m_mct_records; - OPJ_UINT32 i; + opj_read_bytes(l_current_ptr,&l_tccp->qmfbid ,1); /* SPcoc (H) */ + ++l_current_ptr; - for (i=0;im_nb_mct_records;++i) { - if (l_mct_data->m_data) { - opj_free(l_mct_data->m_data); - l_mct_data->m_data = 00; - } + *p_header_size = *p_header_size - 5; - ++l_mct_data; + /* use custom precinct size ? */ + if (l_tccp->csty & J2K_CCP_CSTY_PRT) { + if (*p_header_size < l_tccp->numresolutions) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading SPCod SPCoc element\n"); + return OPJ_FALSE; + } + + for (i = 0; i < l_tccp->numresolutions; ++i) { + opj_read_bytes(l_current_ptr,&l_tmp ,1); /* SPcoc (I_i) */ + ++l_current_ptr; + l_tccp->prcw[i] = l_tmp & 0xf; + l_tccp->prch[i] = l_tmp >> 4; } - opj_free(p_tcp->m_mct_records); - p_tcp->m_mct_records = 00; + *p_header_size = *p_header_size - l_tccp->numresolutions; } - - if (p_tcp->mct_norms != 00) { - opj_free(p_tcp->mct_norms); - p_tcp->mct_norms = 00; + else { + /* set default size for the precinct width and height */ + for (i = 0; i < l_tccp->numresolutions; ++i) { + l_tccp->prcw[i] = 15; + l_tccp->prch[i] = 15; + } } - if (p_tcp->m_data) { - opj_free(p_tcp->m_data); - p_tcp->m_data = 00; - } -} +#ifdef WIP_REMOVE_MSD + /* INDEX >> */ + if (p_j2k->cstr_info && compno == 0) { + OPJ_UINT32 l_data_size = l_tccp->numresolutions * sizeof(OPJ_UINT32); + p_j2k->cstr_info->tile[p_j2k->m_current_tile_number].tccp_info[compno].cblkh = l_tccp->cblkh; + p_j2k->cstr_info->tile[p_j2k->m_current_tile_number].tccp_info[compno].cblkw = l_tccp->cblkw; + p_j2k->cstr_info->tile[p_j2k->m_current_tile_number].tccp_info[compno].numresolutions = l_tccp->numresolutions; + p_j2k->cstr_info->tile[p_j2k->m_current_tile_number].tccp_info[compno].cblksty = l_tccp->cblksty; + p_j2k->cstr_info->tile[p_j2k->m_current_tile_number].tccp_info[compno].qmfbid = l_tccp->qmfbid; -/** - * Destroys a coding parameter structure. - * - * @param p_cp the coding parameter to destroy. - */ -void j2k_cp_destroy (opj_cp_v2_t *p_cp) -{ - OPJ_UINT32 l_nb_tiles; - opj_tcp_v2_t * l_current_tile = 00; - OPJ_UINT32 i; - if - (p_cp == 00) - { - return; + memcpy(p_j2k->cstr_info->tile[p_j2k->m_current_tile_number].pdx,l_tccp->prcw, l_data_size); + memcpy(p_j2k->cstr_info->tile[p_j2k->m_current_tile_number].pdy,l_tccp->prch, l_data_size); } - if - (p_cp->tcps != 00) - { - l_current_tile = p_cp->tcps; - l_nb_tiles = p_cp->th * p_cp->tw; + /* << INDEX */ +#endif - for - (i = 0; i < l_nb_tiles; ++i) - { - j2k_tcp_destroy(l_current_tile); - ++l_current_tile; - } - opj_free(p_cp->tcps); - p_cp->tcps = 00; - } - if - (p_cp->ppm_buffer != 00) - { - opj_free(p_cp->ppm_buffer); - p_cp->ppm_buffer = 00; - } - if - (p_cp->comment != 00) - { - opj_free(p_cp->comment); - p_cp->comment = 00; - } - if - (! p_cp->m_is_decoder) - { - if - (p_cp->m_specific_param.m_enc.m_matrice) - { - opj_free(p_cp->m_specific_param.m_enc.m_matrice); - p_cp->m_specific_param.m_enc.m_matrice = 00; - } - } + return OPJ_TRUE; } - - /** - * Reads a tile header. - * @param p_j2k the jpeg2000 codec. - * @param p_stream the stream to write data to. - * @param p_manager the user event manager. + * Copies the tile component parameters of all the component from the first tile component. + * + * @param p_j2k the J2k codec. */ -opj_bool j2k_read_tile_header( opj_j2k_v2_t * p_j2k, - OPJ_UINT32 * p_tile_index, - OPJ_UINT32 * p_data_size, - OPJ_INT32 * p_tile_x0, OPJ_INT32 * p_tile_y0, - OPJ_INT32 * p_tile_x1, OPJ_INT32 * p_tile_y1, - OPJ_UINT32 * p_nb_comps, - opj_bool * p_go_on, - opj_stream_private_t *p_stream, - opj_event_mgr_t * p_manager ) +void j2k_copy_tile_component_parameters( opj_j2k_v2_t *p_j2k ) { - OPJ_UINT32 l_current_marker = J2K_MS_SOT; - OPJ_UINT32 l_marker_size; - const opj_dec_memory_marker_handler_t * l_marker_handler = 00; - opj_tcp_v2_t * l_tcp = NULL; - OPJ_UINT32 l_nb_tiles; + /* loop */ + OPJ_UINT32 i; + opj_cp_v2_t *l_cp = NULL; + opj_tcp_v2_t *l_tcp = NULL; + opj_tccp_t *l_ref_tccp = NULL, *l_copied_tccp = NULL; + OPJ_UINT32 l_prc_size; /* preconditions */ - assert(p_stream != 00); assert(p_j2k != 00); - assert(p_manager != 00); - /* Reach the End Of Codestream ?*/ - if (p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_EOC){ - l_current_marker = J2K_MS_EOC; - } - /* We need to encounter a SOT marker (a new tile-part header) */ - else if (p_j2k->m_specific_param.m_decoder.m_state != J2K_STATE_TPHSOT){ - return OPJ_FALSE; - } - - /* Read into the codestream until reach the EOC or ! can_decode ??? FIXME */ - while ( (!p_j2k->m_specific_param.m_decoder.m_can_decode) && (l_current_marker != J2K_MS_EOC) ) { - - /* Try to read until the Start Of Data is detected */ - while (l_current_marker != J2K_MS_SOD) { - - /* Try to read 2 bytes (the marker size) 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_v2(p_manager, EVT_ERROR, "Stream too short\n"); - return OPJ_FALSE; - } + l_cp = &(p_j2k->m_cp); + l_tcp = (p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_TPH) ? /* FIXME J2K_DEC_STATE_TPH*/ + &l_cp->tcps[p_j2k->m_current_tile_number] : + p_j2k->m_specific_param.m_decoder.m_default_tcp; - /* Read 2 bytes from the buffer as the marker size */ - opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data,&l_marker_size,2); + l_ref_tccp = &l_tcp->tccps[0]; + l_copied_tccp = l_ref_tccp + 1; + l_prc_size = l_ref_tccp->numresolutions * sizeof(OPJ_UINT32); - /* Why this condition? FIXME */ - if (p_j2k->m_specific_param.m_decoder.m_state & J2K_STATE_TPH){ - p_j2k->m_specific_param.m_decoder.m_sot_length -= (l_marker_size + 2); - } - l_marker_size -= 2; /* Subtract the size of the marker ID already read */ + for (i=1; im_private_image->numcomps; ++i) { + l_copied_tccp->numresolutions = l_ref_tccp->numresolutions; + l_copied_tccp->cblkw = l_ref_tccp->cblkw; + l_copied_tccp->cblkh = l_ref_tccp->cblkh; + l_copied_tccp->cblksty = l_ref_tccp->cblksty; + l_copied_tccp->qmfbid = l_ref_tccp->qmfbid; + memcpy(l_copied_tccp->prcw,l_ref_tccp->prcw,l_prc_size); + memcpy(l_copied_tccp->prch,l_ref_tccp->prch,l_prc_size); + ++l_copied_tccp; + } +} - /* Get the marker handler from the marker ID */ - l_marker_handler = j2k_get_marker_handler(l_current_marker); +/** + * Gets the size taken by writing SQcd or SQcc element, i.e. the quantization values of a band in the QCD or QCC. + * + * @param p_tile_no the tile index. + * @param p_comp_no the component being outputted. + * @param p_j2k the J2K codec. + * + * @return the number of bytes taken by the SPCod element. + */ +OPJ_UINT32 j2k_get_SQcd_SQcc_size ( opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no ) +{ + OPJ_UINT32 l_num_bands; - /* Check if the marker is known and if it is the right place to find it */ - if (! (p_j2k->m_specific_param.m_decoder.m_state & l_marker_handler->states) ) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Marker is not compliant with its position\n"); - return OPJ_FALSE; - } -/* FIXME manage case of unknown marker as in the main header ? */ + opj_cp_v2_t *l_cp = 00; + opj_tcp_v2_t *l_tcp = 00; + opj_tccp_t *l_tccp = 00; - /* Check if the marker size is compatible with the header data size */ - if (l_marker_size > p_j2k->m_specific_param.m_decoder.m_header_data_size) { - p_j2k->m_specific_param.m_decoder.m_header_data = (OPJ_BYTE*) - opj_realloc(p_j2k->m_specific_param.m_decoder.m_header_data,l_marker_size); - if (p_j2k->m_specific_param.m_decoder.m_header_data == 00) { - return OPJ_FALSE; - } - p_j2k->m_specific_param.m_decoder.m_header_data_size = l_marker_size; - } + /* preconditions */ + assert(p_j2k != 00); - /* Try to read the rest of the marker segment 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,l_marker_size,p_manager) != l_marker_size) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Stream too short\n"); - return OPJ_FALSE; - } + l_cp = &(p_j2k->m_cp); + l_tcp = &l_cp->tcps[p_tile_no]; + l_tccp = &l_tcp->tccps[p_comp_no]; - /* Read the marker segment with the correct marker handler */ - if (! (*(l_marker_handler->handler))(p_j2k,p_j2k->m_specific_param.m_decoder.m_header_data,l_marker_size,p_manager)) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Fail to read the current marker segment (%#x)\n", l_current_marker); - return OPJ_FALSE; - } + /* preconditions again */ + assert(p_tile_no < l_cp->tw * l_cp->th); + assert(p_comp_no < p_j2k->m_private_image->numcomps); - /* Add the marker to the codestream index*/ - j2k_add_tlmarker_v2(p_j2k->m_current_tile_number, - p_j2k->cstr_index, - l_marker_handler->id, - (OPJ_UINT32) opj_stream_tell(p_stream) - l_marker_size - 4, - l_marker_size + 4 ); + l_num_bands = (l_tccp->qntsty == J2K_CCP_QNTSTY_SIQNT) ? 1 : (l_tccp->numresolutions * 3 - 2); - /* Keep the position of the last SOT marker read */ - if ( l_marker_handler->id == J2K_MS_SOT ) { - OPJ_UINT32 sot_pos = (OPJ_UINT32) opj_stream_tell(p_stream) - l_marker_size - 4 ; - if (sot_pos > p_j2k->m_specific_param.m_decoder.m_last_sot_read_pos) - { - p_j2k->m_specific_param.m_decoder.m_last_sot_read_pos = sot_pos; - } - } + if (l_tccp->qntsty == J2K_CCP_QNTSTY_NOQNT) { + return 1 + l_num_bands; + } + else { + return 1 + 2*l_num_bands; + } +} +/** + * Writes a SQcd or SQcc element, i.e. the quantization values of a band. + * + * @param p_tile_no the tile to output. + * @param p_comp_no the component number to output. + * @param p_data the data buffer. + * @param p_header_size pointer to the size of the data buffer, it is changed by the function. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. + * +*/ +opj_bool j2k_write_SQcd_SQcc( opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_header_size, + struct opj_event_mgr * p_manager ) +{ + OPJ_UINT32 l_header_size; + OPJ_UINT32 l_band_no, l_num_bands; + OPJ_UINT32 l_expn,l_mant; - if (p_j2k->m_specific_param.m_decoder.m_skip_data) { - /* Skip the rest of the tile part header*/ - if (opj_stream_skip(p_stream,p_j2k->m_specific_param.m_decoder.m_sot_length,p_manager) != p_j2k->m_specific_param.m_decoder.m_sot_length) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Stream too short\n"); - return OPJ_FALSE; - } - l_current_marker = J2K_MS_SOD; /* Normally we reached a SOD */ - } - else { - /* 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_v2(p_manager, EVT_ERROR, "Stream too short\n"); - return OPJ_FALSE; - } - /* Read 2 bytes from the buffer as the new marker ID */ - opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data,&l_current_marker,2); - } - } + opj_cp_v2_t *l_cp = 00; + opj_tcp_v2_t *l_tcp = 00; + opj_tccp_t *l_tccp = 00; - /* If we didn't skip data before, we need to read the SOD marker*/ - if (! p_j2k->m_specific_param.m_decoder.m_skip_data) { - /* Try to read the SOD marker and skip data ? FIXME */ - if (! j2k_read_sod_v2(p_j2k, p_stream, p_manager)) { - return OPJ_FALSE; - } + /* preconditions */ + assert(p_j2k != 00); + assert(p_header_size != 00); + assert(p_manager != 00); + assert(p_data != 00); + l_cp = &(p_j2k->m_cp); + l_tcp = &l_cp->tcps[p_tile_no]; + l_tccp = &l_tcp->tccps[p_comp_no]; + /* preconditions again */ + assert(p_tile_no < l_cp->tw * l_cp->th); + assert(p_comp_no m_private_image->numcomps); - 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_v2(p_manager, EVT_ERROR, "Stream too short\n"); - return OPJ_FALSE; - } + l_num_bands = (l_tccp->qntsty == J2K_CCP_QNTSTY_SIQNT) ? 1 : (l_tccp->numresolutions * 3 - 2); - /* 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); - } + if (l_tccp->qntsty == J2K_CCP_QNTSTY_NOQNT) { + l_header_size = 1 + l_num_bands; + + if (*p_header_size < l_header_size) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error writing SQcd SQcc element\n"); + return OPJ_FALSE; } - 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; - /* 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_v2(p_manager, EVT_ERROR, "Stream too short\n"); - return OPJ_FALSE; - } + opj_write_bytes(p_data,l_tccp->qntsty + (l_tccp->numgbits << 5), 1); /* Sqcx */ + ++p_data; - /* 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); + for (l_band_no = 0; l_band_no < l_num_bands; ++l_band_no) { + l_expn = l_tccp->stepsizes[l_band_no].expn; + opj_write_bytes(p_data, l_expn << 3, 1); /* SPqcx_i */ + ++p_data; } } + else { + l_header_size = 1 + 2*l_num_bands; - /* Current marker is the EOC marker ?*/ - if (l_current_marker == J2K_MS_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; + if (*p_header_size < l_header_size) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error writing SQcd SQcc element\n"); + return OPJ_FALSE; } - } - /* FIXME DOC ???*/ - if ( ! p_j2k->m_specific_param.m_decoder.m_can_decode) { - l_tcp = p_j2k->m_cp.tcps + p_j2k->m_current_tile_number; - l_nb_tiles = p_j2k->m_cp.th * p_j2k->m_cp.tw; + opj_write_bytes(p_data,l_tccp->qntsty + (l_tccp->numgbits << 5), 1); /* Sqcx */ + ++p_data; - while( (p_j2k->m_current_tile_number < l_nb_tiles) && (l_tcp->m_data == 00) ) { - ++p_j2k->m_current_tile_number; - ++l_tcp; - } + for (l_band_no = 0; l_band_no < l_num_bands; ++l_band_no) { + l_expn = l_tccp->stepsizes[l_band_no].expn; + l_mant = l_tccp->stepsizes[l_band_no].mant; - if (p_j2k->m_current_tile_number == l_nb_tiles) { - *p_go_on = OPJ_FALSE; - return OPJ_TRUE; + opj_write_bytes(p_data, (l_expn << 11) + l_mant, 2); /* SPqcx_i */ + p_data += 2; } } - /*FIXME ???*/ - if (! tcd_init_decode_tile(p_j2k->m_tcd, p_j2k->m_current_tile_number)) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Cannot decode tile, memory error\n"); - return OPJ_FALSE; - } - - opj_event_msg_v2(p_manager, EVT_INFO, "Header of tile %d / %d has been read.\n", - p_j2k->m_current_tile_number, (p_j2k->m_cp.th * p_j2k->m_cp.tw) - 1); - - *p_tile_index = p_j2k->m_current_tile_number; - *p_go_on = OPJ_TRUE; - *p_data_size = tcd_get_decoded_tile_size(p_j2k->m_tcd); - *p_tile_x0 = p_j2k->m_tcd->tcd_image->tiles->x0; - *p_tile_y0 = p_j2k->m_tcd->tcd_image->tiles->y0; - *p_tile_x1 = p_j2k->m_tcd->tcd_image->tiles->x1; - *p_tile_y1 = p_j2k->m_tcd->tcd_image->tiles->y1; - *p_nb_comps = p_j2k->m_tcd->tcd_image->tiles->numcomps; - - p_j2k->m_specific_param.m_decoder.m_state |= 0x0080;// FIXME J2K_DEC_STATE_DATA; + *p_header_size = *p_header_size - l_header_size; return OPJ_TRUE; } - -opj_bool j2k_decode_tile ( opj_j2k_v2_t * p_j2k, - OPJ_UINT32 p_tile_index, - OPJ_BYTE * p_data, - OPJ_UINT32 p_data_size, - opj_stream_private_t *p_stream, - opj_event_mgr_t * p_manager ) +/** + * Reads a SQcd or SQcc element, i.e. the quantization values of a band. + * + * @param p_comp_no the component being targeted. + * @param p_header_data the data contained in the COM box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the COM marker. + * @param p_manager the user event manager. +*/ +opj_bool j2k_read_SQcd_SQcc( + opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_comp_no, + OPJ_BYTE* p_header_data, + OPJ_UINT32 * p_header_size, + struct opj_event_mgr * p_manager + ) { - OPJ_UINT32 l_current_marker; - OPJ_BYTE l_data [2]; - opj_tcp_v2_t * l_tcp; + /* loop*/ + OPJ_UINT32 l_band_no; + opj_cp_v2_t *l_cp = 00; + opj_tcp_v2_t *l_tcp = 00; + opj_tccp_t *l_tccp = 00; + OPJ_BYTE * l_current_ptr = 00; + OPJ_UINT32 l_tmp, l_num_band; - /* preconditions */ - assert(p_stream != 00); + /* preconditions*/ assert(p_j2k != 00); assert(p_manager != 00); + assert(p_header_data != 00); - if ( !(p_j2k->m_specific_param.m_decoder.m_state & 0x0080/*FIXME J2K_DEC_STATE_DATA*/) - || (p_tile_index != p_j2k->m_current_tile_number) ) { - return OPJ_FALSE; - } + l_cp = &(p_j2k->m_cp); + /* come from tile part header or main header ?*/ + l_tcp = (p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_TPH) ? /*FIXME J2K_DEC_STATE_TPH*/ + &l_cp->tcps[p_j2k->m_current_tile_number] : + p_j2k->m_specific_param.m_decoder.m_default_tcp; - l_tcp = &(p_j2k->m_cp.tcps[p_tile_index]); - if (! l_tcp->m_data) { - j2k_tcp_destroy(&l_tcp); - return OPJ_FALSE; - } + /* precondition again*/ + assert(p_comp_no < p_j2k->m_private_image->numcomps); - if (! tcd_decode_tile_v2( p_j2k->m_tcd, - l_tcp->m_data, - l_tcp->m_data_size, - p_tile_index, - p_j2k->cstr_index) ) { - j2k_tcp_destroy(l_tcp); - p_j2k->m_specific_param.m_decoder.m_state |= 0x8000;//FIXME J2K_DEC_STATE_ERR; - return OPJ_FALSE; - } + l_tccp = &l_tcp->tccps[p_comp_no]; + l_current_ptr = p_header_data; - if (! tcd_update_tile_data(p_j2k->m_tcd,p_data,p_data_size)) { + if (*p_header_size < 1) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading SQcd or SQcc element\n"); return OPJ_FALSE; } + *p_header_size -= 1; - j2k_tcp_destroy(l_tcp); - p_j2k->m_tcd->tcp = 0; + opj_read_bytes(l_current_ptr, &l_tmp ,1); /* Sqcx */ + ++l_current_ptr; - p_j2k->m_specific_param.m_decoder.m_can_decode = 0; - p_j2k->m_specific_param.m_decoder.m_state &= (~ (0x0080));// FIXME J2K_DEC_STATE_DATA); + l_tccp->qntsty = l_tmp & 0x1f; + l_tccp->numgbits = l_tmp >> 5; + if (l_tccp->qntsty == J2K_CCP_QNTSTY_SIQNT) { + l_num_band = 1; + } + else { + l_num_band = (l_tccp->qntsty == J2K_CCP_QNTSTY_NOQNT) ? + (*p_header_size) : + (*p_header_size) / 2; - if (p_j2k->m_specific_param.m_decoder.m_state != 0x0100){ //FIXME J2K_DEC_STATE_EOC) - if (opj_stream_read_data(p_stream,l_data,2,p_manager) != 2) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Stream too short\n"); - return OPJ_FALSE; + if( l_num_band > J2K_MAXBANDS ) { + opj_event_msg_v2(p_manager, EVT_WARNING, "While reading CCP_QNTSTY element inside QCD or QCC marker segment, " + "number of subbands (%d) is greater to J2K_MAXBANDS (%d). So we limit the number of elements stored to " + "J2K_MAXBANDS (%d) and skip the rest. \n", l_num_band, J2K_MAXBANDS, J2K_MAXBANDS); + /*return OPJ_FALSE;*/ } + } - opj_read_bytes(l_data,&l_current_marker,2); +#ifdef USE_JPWL + if (l_cp->correct) { - if (l_current_marker == J2K_MS_EOC) { - p_j2k->m_current_tile_number = 0; - p_j2k->m_specific_param.m_decoder.m_state = 0x0100;//FIXME J2K_DEC_STATE_EOC; + /* if JPWL is on, we check whether there are too many subbands */ + if (/*(l_num_band < 0) ||*/ (l_num_band >= J2K_MAXBANDS)) { + opj_event_msg_v2(p_manager, JPWL_ASSUME ? EVT_WARNING : EVT_ERROR, + "JPWL: bad number of subbands in Sqcx (%d)\n", + l_num_band); + if (!JPWL_ASSUME) { + opj_event_msg_v2(p_manager, EVT_ERROR, "JPWL: giving up\n"); + return OPJ_FALSE; + } + /* we try to correct */ + l_num_band = 1; + opj_event_msg_v2(p_manager, EVT_WARNING, "- trying to adjust them\n" + "- setting number of bands to %d => HYPOTHESIS!!!\n", + l_num_band); + }; + + }; +#endif /* USE_JPWL */ + + if (l_tccp->qntsty == J2K_CCP_QNTSTY_NOQNT) { + for (l_band_no = 0; l_band_no < l_num_band; l_band_no++) { + opj_read_bytes(l_current_ptr, &l_tmp ,1); /* SPqcx_i */ + ++l_current_ptr; + if (l_band_no < J2K_MAXBANDS){ + l_tccp->stepsizes[l_band_no].expn = l_tmp>>3; + l_tccp->stepsizes[l_band_no].mant = 0; + } } - else if (l_current_marker != J2K_MS_SOT) - { - opj_event_msg_v2(p_manager, EVT_ERROR, "Stream too short, expected SOT\n"); - return OPJ_FALSE; + *p_header_size = *p_header_size - l_num_band; + } + else { + for (l_band_no = 0; l_band_no < l_num_band; l_band_no++) { + opj_read_bytes(l_current_ptr, &l_tmp ,2); /* SPqcx_i */ + l_current_ptr+=2; + if (l_band_no < J2K_MAXBANDS){ + l_tccp->stepsizes[l_band_no].expn = l_tmp >> 11; + l_tccp->stepsizes[l_band_no].mant = l_tmp & 0x7ff; + } + } + *p_header_size = *p_header_size - 2*l_num_band; + } + + /* Add Antonin : if scalar_derived -> compute other stepsizes */ + if (l_tccp->qntsty == J2K_CCP_QNTSTY_SIQNT) { + for (l_band_no = 1; l_band_no < J2K_MAXBANDS; l_band_no++) { + l_tccp->stepsizes[l_band_no].expn = + ((l_tccp->stepsizes[0].expn) - ((l_band_no - 1) / 3) > 0) ? + (l_tccp->stepsizes[0].expn) - ((l_band_no - 1) / 3) : 0; + l_tccp->stepsizes[l_band_no].mant = l_tccp->stepsizes[0].mant; } } return OPJ_TRUE; } - -opj_bool j2k_update_image_data (opj_tcd_v2_t * p_tcd, OPJ_BYTE * p_data, opj_image_t* p_output_image) +/** + * Copies the tile component parameters of all the component from the first tile component. + * + * @param p_j2k the J2k codec. + */ +void j2k_copy_tile_quantization_parameters( opj_j2k_v2_t *p_j2k ) { - OPJ_UINT32 i,j,k = 0; - 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_INT32 l_start_offset_src, l_line_offset_src, l_end_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_INT32 l_start_offset_dest, l_line_offset_dest; + OPJ_UINT32 i; + opj_cp_v2_t *l_cp = NULL; + opj_tcp_v2_t *l_tcp = NULL; + opj_tccp_t *l_ref_tccp = NULL; + opj_tccp_t *l_copied_tccp = NULL; + OPJ_UINT32 l_size; - opj_image_comp_t * l_img_comp_src = 00; - opj_image_comp_t * l_img_comp_dest = 00; + /* preconditions */ + assert(p_j2k != 00); - opj_tcd_tilecomp_v2_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_v2_t* l_res= 00; + l_cp = &(p_j2k->m_cp); + l_tcp = p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_TPH ? + &l_cp->tcps[p_j2k->m_current_tile_number] : + p_j2k->m_specific_param.m_decoder.m_default_tcp; - l_tilec = p_tcd->tcd_image->tiles->comps; - l_image_src = p_tcd->image; - l_img_comp_src = l_image_src->comps; + l_ref_tccp = &l_tcp->tccps[0]; + l_copied_tccp = l_ref_tccp + 1; + l_size = J2K_MAXBANDS * sizeof(opj_stepsize_t); + + for (i=1;im_private_image->numcomps;++i) { + l_copied_tccp->qntsty = l_ref_tccp->qntsty; + l_copied_tccp->numgbits = l_ref_tccp->numgbits; + memcpy(l_copied_tccp->stepsizes,l_ref_tccp->stepsizes,l_size); + ++l_copied_tccp; + } +} + +/** + * Dump some elements from the J2K decompression structure . + * + *@param p_j2k the jpeg2000 codec. + *@param flag flag to describe what elments are dump. + *@param out_stream output stream where dump the elements. + * +*/ +void j2k_dump (opj_j2k_v2_t* p_j2k, OPJ_INT32 flag, FILE* out_stream) +{ + /* Check if the flag is compatible with j2k file*/ + if ( (flag & OPJ_JP2_INFO) || (flag & OPJ_JP2_IND)){ + fprintf(out_stream, "Wrong flag\n"); + return; + } - l_img_comp_dest = p_output_image->comps; + /* Dump the image_header */ + if (flag & OPJ_IMG_INFO){ + if (p_j2k->m_private_image) + j2k_dump_image_header(p_j2k->m_private_image, 0, out_stream); + } - for (i=0; inumcomps; i++) { + /* Dump the codestream info from main header */ + if (flag & OPJ_J2K_MH_INFO){ + j2k_dump_MH_info(p_j2k, out_stream); + } - /* Allocate output component buffer if necessary */ - if (!l_img_comp_dest->data) { - l_img_comp_dest->data = (OPJ_INT32*) opj_calloc(l_img_comp_dest->w * l_img_comp_dest->h, sizeof(OPJ_INT32)); - if (! l_img_comp_dest->data) { - return OPJ_FALSE; - } - } + /* Dump the codestream info of the current tile */ + if (flag & OPJ_J2K_TH_INFO){ - /* 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; + /* Dump the codestream index from main header */ + if (flag & OPJ_J2K_MH_IND){ + j2k_dump_MH_index(p_j2k, out_stream); + } - if (l_remaining) { - ++l_size_comp; - } + /* Dump the codestream index of the current tile */ + if (flag & OPJ_J2K_TH_IND){ - if (l_size_comp == 3) { - l_size_comp = 4; - } - /*-----*/ + } - /* 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); - }*/ +} - l_width_src = (l_res->x1 - l_res->x0); - l_height_src = (l_res->y1 - l_res->y0); +/** + * Dump index elements of the codestream extract from the main header. + * + *@param p_j2k the jpeg2000 codec. + *@param out_stream output stream where dump the elements. + * +*/ +void j2k_dump_MH_index(opj_j2k_v2_t* p_j2k, FILE* out_stream) +{ + opj_codestream_index_t* cstr_index = p_j2k->cstr_index; + OPJ_UINT32 it_marker, it_tile, it_tile_part; - /* Border of the current output component*/ - l_x0_dest = int_ceildivpow2(l_img_comp_dest->x0, l_img_comp_dest->factor); - l_y0_dest = int_ceildivpow2(l_img_comp_dest->y0, l_img_comp_dest->factor); - l_x1_dest = l_x0_dest + l_img_comp_dest->w; - l_y1_dest = l_y0_dest + l_img_comp_dest->h; + fprintf(out_stream, "Codestream index from main header: {\n"); - /*if (i == 0) { - fprintf(stdout, "DEST: l_x0_dest=%d, l_x1_dest=%d, l_y0_dest=%d, l_y1_dest=%d (%d)\n", - l_x0_dest, l_x1_dest, l_y0_dest, l_y1_dest, l_img_comp_dest->factor ); - }*/ + fprintf(out_stream, "\t Main header start position=%" PRIi64 "\n" + "\t Main header end position=%" PRIi64 "\n", + cstr_index->main_head_start, cstr_index->main_head_end); - /*-----*/ - /* Compute the area (l_offset_x0_src, l_offset_y0_src, l_offset_x1_src, l_offset_y1_src) - * of the input buffer (decoded tile component) which will be move - * in the output buffer. Compute the area of the output buffer (l_start_x_dest, - * l_start_y_dest, l_width_dest, l_height_dest) which will be modified - * by this input area. - * */ - if ( l_x0_dest < l_res->x0 ) { - l_start_x_dest = l_res->x0 - l_x0_dest; - l_offset_x0_src = 0; + fprintf(out_stream, "\t Marker list: {\n"); - if ( l_x1_dest >= l_res->x1 ) { - l_width_dest = l_width_src; - l_offset_x1_src = 0; - } - else { - l_width_dest = l_x1_dest - l_res->x0 ; - l_offset_x1_src = l_width_src - l_width_dest; - } + if (cstr_index->marker){ + for (it_marker=0; it_marker < cstr_index->marknum ; it_marker++){ + fprintf(out_stream, "\t\t type=%#x, pos=%" PRIi64 ", len=%d\n", + cstr_index->marker[it_marker].type, + cstr_index->marker[it_marker].pos, + cstr_index->marker[it_marker].len ); } - else { - l_start_x_dest = 0 ; - l_offset_x0_src = l_x0_dest - l_res->x0; + } - if ( l_x1_dest >= l_res->x1 ) { - l_width_dest = l_width_src - 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 - l_x1_dest; - } - } + fprintf(out_stream, "\t }\n"); - if ( l_y0_dest < l_res->y0 ) { - l_start_y_dest = l_res->y0 - l_y0_dest; - l_offset_y0_src = 0; - if ( l_y1_dest >= l_res->y1 ) { - l_height_dest = l_height_src; - l_offset_y1_src = 0; - } - else { - l_height_dest = l_y1_dest - l_res->y0 ; - l_offset_y1_src = l_height_src - l_height_dest; - } - } - else { - l_start_y_dest = 0 ; - l_offset_y0_src = l_y0_dest - l_res->y0; + if (cstr_index->tile_index){ - if ( l_y1_dest >= l_res->y1 ) { - l_height_dest = l_height_src - 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 - l_y1_dest; - } - } + /* Simple test to avoid to write empty information*/ + OPJ_UINT32 l_acc_nb_of_tile_part = 0; + for (it_tile=0; it_tile < cstr_index->nb_of_tiles ; it_tile++){ + l_acc_nb_of_tile_part += cstr_index->tile_index[it_tile].nb_tps; + } + + if (l_acc_nb_of_tile_part) + { + fprintf(out_stream, "\t Tile index: {\n"); + + for (it_tile=0; it_tile < cstr_index->nb_of_tiles ; it_tile++){ + OPJ_UINT32 nb_of_tile_part = cstr_index->tile_index[it_tile].nb_tps; + + fprintf(out_stream, "\t\t nb of tile-part in tile [%d]=%d\n", it_tile, nb_of_tile_part); + + if (cstr_index->tile_index[it_tile].tp_index){ + for (it_tile_part =0; it_tile_part < nb_of_tile_part; it_tile_part++){ + fprintf(out_stream, "\t\t\t tile-part[%d]: star_pos=%" PRIi64 ", end_header=%" PRIi64 ", end_pos=%" PRIi64 ".\n", + it_tile_part, + cstr_index->tile_index[it_tile].tp_index[it_tile_part].start_pos, + cstr_index->tile_index[it_tile].tp_index[it_tile_part].end_header, + cstr_index->tile_index[it_tile].tp_index[it_tile_part].end_pos); + } + } + + if (cstr_index->tile_index[it_tile].marker){ + for (it_marker=0; it_marker < cstr_index->tile_index[it_tile].marknum ; it_marker++){ + fprintf(out_stream, "\t\t type=%#x, pos=%" PRIi64 ", len=%d\n", + cstr_index->tile_index[it_tile].marker[it_marker].type, + cstr_index->tile_index[it_tile].marker[it_marker].pos, + cstr_index->tile_index[it_tile].marker[it_marker].len ); + } + } + } + fprintf(out_stream,"\t }\n"); + } + } - if( (l_offset_x0_src < 0 ) || (l_offset_y0_src < 0 ) || (l_offset_x1_src < 0 ) || (l_offset_y1_src < 0 ) ){ - return OPJ_FALSE; - } - /*-----*/ + fprintf(out_stream,"}\n"); - /* Compute the input buffer offset */ - l_start_offset_src = l_offset_x0_src + l_offset_y0_src * l_width_src; - l_line_offset_src = l_offset_x1_src + l_offset_x0_src; - l_end_offset_src = l_offset_y1_src * l_width_src - l_offset_x0_src; +} - /* Compute the output buffer offset */ - l_start_offset_dest = l_start_x_dest + l_start_y_dest * l_img_comp_dest->w; - l_line_offset_dest = l_img_comp_dest->w - l_width_dest; +/** + * Dump info elements of the codestream extract from the main header. + * + *@param p_j2k the jpeg2000 codec. + *@param out_stream output stream where dump the elements. + * +*/ +void j2k_dump_MH_info(opj_j2k_v2_t* p_j2k, FILE* out_stream) +{ + opj_tcp_v2_t * l_default_tile=NULL; - /* Move the output buffer to the first place where we will write*/ - l_dest_ptr = l_img_comp_dest->data + l_start_offset_dest; + fprintf(out_stream, "Codestream info from main header: {\n"); - /*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(out_stream, "\t tx0=%d, ty0=%d\n", p_j2k->m_cp.tx0, p_j2k->m_cp.ty0); + fprintf(out_stream, "\t tdx=%d, tdy=%d\n", p_j2k->m_cp.tdx, p_j2k->m_cp.tdy); + fprintf(out_stream, "\t tw=%d, th=%d\n", p_j2k->m_cp.tw, p_j2k->m_cp.th); - 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); - }*/ + l_default_tile = p_j2k->m_specific_param.m_decoder.m_default_tcp; + if (l_default_tile) + { + OPJ_INT32 compno; + OPJ_INT32 numcomps = p_j2k->m_private_image->numcomps; + fprintf(out_stream, "\t default tile {\n"); + fprintf(out_stream, "\t\t csty=%#x\n", l_default_tile->csty); + fprintf(out_stream, "\t\t prg=%#x\n", l_default_tile->prg); + fprintf(out_stream, "\t\t numlayers=%d\n", l_default_tile->numlayers); + fprintf(out_stream, "\t\t mct=%x\n", l_default_tile->mct); - 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*/ + for (compno = 0; compno < numcomps; compno++) { + opj_tccp_t *l_tccp = &(l_default_tile->tccps[compno]); + OPJ_UINT32 resno; + OPJ_INT32 bandno, numbands; - 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 */ - } + /* coding style*/ + fprintf(out_stream, "\t\t comp %d {\n", compno); + fprintf(out_stream, "\t\t\t csty=%#x\n", l_tccp->csty); + fprintf(out_stream, "\t\t\t numresolutions=%d\n", l_tccp->numresolutions); + fprintf(out_stream, "\t\t\t cblkw=2^%d\n", l_tccp->cblkw); + fprintf(out_stream, "\t\t\t cblkh=2^%d\n", l_tccp->cblkh); + fprintf(out_stream, "\t\t\t cblksty=%#x\n", l_tccp->cblksty); + fprintf(out_stream, "\t\t\t qmfbid=%d\n", l_tccp->qmfbid); - 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 */ - } - } - 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); - } + fprintf(out_stream, "\t\t\t preccintsize (w,h)="); + for (resno = 0; resno < l_tccp->numresolutions; resno++) { + fprintf(out_stream, "(%d,%d) ", l_tccp->prcw[resno], l_tccp->prch[resno]); + } + fprintf(out_stream, "\n"); - l_dest_ptr+= l_line_offset_dest; - l_src_ptr += l_line_offset_src; - } - } + /* quantization style*/ + fprintf(out_stream, "\t\t\t qntsty=%d\n", l_tccp->qntsty); + fprintf(out_stream, "\t\t\t numgbits=%d\n", l_tccp->numgbits); + fprintf(out_stream, "\t\t\t stepsizes (m,e)="); + numbands = (l_tccp->qntsty == J2K_CCP_QNTSTY_SIQNT) ? 1 : l_tccp->numresolutions * 3 - 2; + for (bandno = 0; bandno < numbands; bandno++) { + fprintf(out_stream, "(%d,%d) ", l_tccp->stepsizes[bandno].mant, + l_tccp->stepsizes[bandno].expn); + } + fprintf(out_stream, "\n"); - 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 */ - } - break; - case 2: - { - OPJ_INT16 * l_src_ptr = (OPJ_INT16 *) p_data; - l_src_ptr += l_start_offset_src; + /* RGN value*/ + fprintf(out_stream, "\t\t\t roishift=%d\n", l_tccp->roishift); - if (l_img_comp_src->sgnd) { - for (j=0;jx0, img_header->y0); + fprintf(out_stream, "%s x1=%d, y1=%d\n", tab, img_header->x1, img_header->y1); + fprintf(out_stream, "%s numcomps=%d\n", tab, img_header->numcomps); - l_src_ptr += l_end_offset_src; - p_data = (OPJ_BYTE*) l_src_ptr; - } - break; + if (img_header->comps){ + OPJ_UINT32 compno; + for (compno = 0; compno < img_header->numcomps; compno++) { + fprintf(out_stream, "%s\t component %d {\n", tab, compno); + j2k_dump_image_comp_header(&(img_header->comps[compno]), dev_dump_flag, out_stream); + fprintf(out_stream,"%s}\n",tab); } - - ++l_img_comp_dest; - ++l_img_comp_src; - ++l_tilec; } - return OPJ_TRUE; + fprintf(out_stream, "}\n"); } /** - * Sets the given area to be decoded. This function should be called right after opj_read_header and before any tile header reading. - * - * @param p_j2k the jpeg2000 codec. - * @param p_start_x the left position of the rectangle to decode (in image coordinates). - * @param p_end_x the right position of the rectangle to decode (in image coordinates). - * @param p_start_y the up position of the rectangle to decode (in image coordinates). - * @param p_end_y the bottom position of the rectangle to decode (in image coordinates). - * @param p_manager the user event manager + * Dump a component image header structure. * - * @return true if the area could be set. + *@param comp_header the component image header to dump. + *@param dev_dump_flag flag to describe if we are in the case of this function is use outside j2k_dump function + *@param out_stream output stream where dump the elements. */ -opj_bool j2k_set_decode_area( opj_j2k_v2_t *p_j2k, - opj_image_t* p_image, - OPJ_INT32 p_start_x, OPJ_INT32 p_start_y, - OPJ_INT32 p_end_x, OPJ_INT32 p_end_y, - struct opj_event_mgr * p_manager ) +void j2k_dump_image_comp_header(opj_image_comp_t* comp_header, opj_bool dev_dump_flag, FILE* out_stream) { - opj_cp_v2_t * l_cp = &(p_j2k->m_cp); - opj_image_t * l_image = p_j2k->m_private_image; - - OPJ_UINT32 it_comp; - OPJ_INT32 l_comp_x1, l_comp_y1; - opj_image_comp_t* l_img_comp = NULL; + char tab[3]; - /* Check if we are read the main header */ - if (p_j2k->m_specific_param.m_decoder.m_state != J2K_STATE_TPHSOT) { // FIXME J2K_DEC_STATE_TPHSOT) - opj_event_msg_v2(p_manager, EVT_ERROR, "Need to decode the main header before begin to decode the remaining codestream"); - return OPJ_FALSE; + if (dev_dump_flag){ + fprintf(stdout, "[DEV] Dump an image_comp_header struct {\n"); + tab[0] = '\0'; + } else { + tab[0] = '\t';tab[1] = '\t';tab[2] = '\0'; } - if ( !p_start_x && !p_start_y && !p_end_x && !p_end_y){ - opj_event_msg_v2(p_manager, EVT_INFO, "No decoded area parameters, set the decoded area to the all image\n"); + fprintf(out_stream, "%s dx=%d, dy=%d\n", tab, comp_header->dx, comp_header->dy); + fprintf(out_stream, "%s prec=%d\n", tab, comp_header->prec); + fprintf(out_stream, "%s sgnd=%d\n", tab, comp_header->sgnd); - p_j2k->m_specific_param.m_decoder.m_start_tile_x = 0; - p_j2k->m_specific_param.m_decoder.m_start_tile_y = 0; - p_j2k->m_specific_param.m_decoder.m_end_tile_x = l_cp->tw; - p_j2k->m_specific_param.m_decoder.m_end_tile_y = l_cp->th; + if (dev_dump_flag) + fprintf(out_stream, "}\n"); +} - return OPJ_TRUE; - } - /* ----- */ - /* Check if the positions provided by the user are correct */ +/** + * Get the codestream info from a JPEG2000 codec. + * + *@param p_j2k the component image header to dump. + * + *@return the codestream information extract from the jpg2000 codec + */ +opj_codestream_info_v2_t* j2k_get_cstr_info(opj_j2k_v2_t* p_j2k) +{ + OPJ_UINT16 compno; + OPJ_UINT16 numcomps = p_j2k->m_private_image->numcomps; + opj_tcp_v2_t *l_default_tile; + opj_codestream_info_v2_t* cstr_info = (opj_codestream_info_v2_t*) opj_calloc(1,sizeof(opj_codestream_info_v2_t)); - /* Left */ - if (p_start_x > l_image->x1 ) { - opj_event_msg_v2(p_manager, EVT_ERROR, - "Left position of the decoded area (region_x0=%d) is outside the image area (Xsiz=%d).\n", - p_start_x, l_image->x1); - return OPJ_FALSE; - } - else if (p_start_x < l_image->x0){ - opj_event_msg_v2(p_manager, EVT_WARNING, - "Left position of the decoded area (region_x0=%d) is outside the image area (XOsiz=%d).\n", - p_start_x, l_image->x0); - p_j2k->m_specific_param.m_decoder.m_start_tile_x = 0; - p_image->x0 = l_image->x0; - } - else { - p_j2k->m_specific_param.m_decoder.m_start_tile_x = (p_start_x - l_cp->tx0) / l_cp->tdx; - p_image->x0 = p_start_x; - } + cstr_info->nbcomps = p_j2k->m_private_image->numcomps; - /* Up */ - if (p_start_y > l_image->y1){ - opj_event_msg_v2(p_manager, EVT_ERROR, - "Up position of the decoded area (region_y0=%d) is outside the image area (Ysiz=%d).\n", - p_start_y, l_image->y1); - return OPJ_FALSE; - } - else if (p_start_y < l_image->y0){ - opj_event_msg_v2(p_manager, EVT_WARNING, - "Up position of the decoded area (region_y0=%d) is outside the image area (YOsiz=%d).\n", - p_start_y, l_image->y0); - p_j2k->m_specific_param.m_decoder.m_start_tile_y = 0; - p_image->y0 = l_image->y0; - } - else { - p_j2k->m_specific_param.m_decoder.m_start_tile_y = (p_start_y - l_cp->ty0) / l_cp->tdy; - p_image->y0 = p_start_y; - } + cstr_info->tx0 = p_j2k->m_cp.tx0; + cstr_info->ty0 = p_j2k->m_cp.ty0; + cstr_info->tdx = p_j2k->m_cp.tdx; + cstr_info->tdy = p_j2k->m_cp.tdy; + cstr_info->tw = p_j2k->m_cp.tw; + cstr_info->th = p_j2k->m_cp.th; - /* Right */ - if (p_end_x < l_image->x0) { - opj_event_msg_v2(p_manager, EVT_ERROR, - "Right position of the decoded area (region_x1=%d) is outside the image area (XOsiz=%d).\n", - p_end_x, l_image->x0); - return OPJ_FALSE; - } - else if (p_end_x > l_image->x1) { - opj_event_msg_v2(p_manager, EVT_WARNING, - "Right position of the decoded area (region_x1=%d) is outside the image area (Xsiz=%d).\n", - p_end_x, l_image->x1); - p_j2k->m_specific_param.m_decoder.m_end_tile_x = l_cp->tw; - p_image->x1 = l_image->x1; - } - else { - p_j2k->m_specific_param.m_decoder.m_end_tile_x = int_ceildiv((p_end_x - l_cp->tx0), l_cp->tdx); - p_image->x1 = p_end_x; - } + cstr_info->tile_info = NULL; /* Not fill from the main header*/ - /* Bottom */ - if (p_end_y < l_image->y0) { - opj_event_msg_v2(p_manager, EVT_ERROR, - "Right position of the decoded area (region_y1=%d) is outside the image area (YOsiz=%d).\n", - p_end_y, l_image->y0); - return OPJ_FALSE; - } - if (p_end_y > l_image->y1){ - opj_event_msg_v2(p_manager, EVT_WARNING, - "Bottom position of the decoded area (region_y1=%d) is outside the image area (Ysiz=%d).\n", - p_end_y, l_image->y1); - p_j2k->m_specific_param.m_decoder.m_end_tile_y = l_cp->th; - p_image->y1 = l_image->y1; - } - else{ - p_j2k->m_specific_param.m_decoder.m_end_tile_y = int_ceildiv((p_end_y - l_cp->ty0), l_cp->tdy); - p_image->y1 = p_end_y; - } - /* ----- */ + l_default_tile = p_j2k->m_specific_param.m_decoder.m_default_tcp; - p_j2k->m_specific_param.m_decoder.m_discard_tiles = 1; + cstr_info->m_default_tile_info.csty = l_default_tile->csty; + cstr_info->m_default_tile_info.prg = l_default_tile->prg; + cstr_info->m_default_tile_info.numlayers = l_default_tile->numlayers; + cstr_info->m_default_tile_info.mct = l_default_tile->mct; - l_img_comp = p_image->comps; - for (it_comp=0; it_comp < p_image->numcomps; ++it_comp) - { - OPJ_INT32 l_h,l_w; + cstr_info->m_default_tile_info.tccp_info = (opj_tccp_info_t*) opj_calloc(cstr_info->nbcomps, sizeof(opj_tccp_info_t)); - l_img_comp->x0 = int_ceildiv(p_image->x0, l_img_comp->dx); - l_img_comp->y0 = int_ceildiv(p_image->y0, l_img_comp->dy); - l_comp_x1 = int_ceildiv(p_image->x1, l_img_comp->dx); - l_comp_y1 = int_ceildiv(p_image->y1, l_img_comp->dy); + for (compno = 0; compno < numcomps; compno++) { + opj_tccp_t *l_tccp = &(l_default_tile->tccps[compno]); + opj_tccp_info_t *l_tccp_info = &(cstr_info->m_default_tile_info.tccp_info[compno]); + OPJ_INT32 bandno, numbands; - l_w = int_ceildivpow2(l_comp_x1, l_img_comp->factor) - - int_ceildivpow2(l_img_comp->x0, l_img_comp->factor); - if (l_w < 0){ - opj_event_msg_v2(p_manager, EVT_ERROR, - "Size x of the decoded component image is incorrect (comp[%d].w=%d).\n", - it_comp, l_w); - return OPJ_FALSE; + /* coding style*/ + l_tccp_info->csty = l_tccp->csty; + l_tccp_info->numresolutions = l_tccp->numresolutions; + l_tccp_info->cblkw = l_tccp->cblkw; + l_tccp_info->cblkh = l_tccp->cblkh; + l_tccp_info->cblksty = l_tccp->cblksty; + l_tccp_info->qmfbid = l_tccp->qmfbid; + if (l_tccp->numresolutions < J2K_MAXRLVLS) + { + memcpy(l_tccp_info->prch, l_tccp->prch, l_tccp->numresolutions); + memcpy(l_tccp_info->prcw, l_tccp->prcw, l_tccp->numresolutions); } - l_img_comp->w = l_w; - l_h = int_ceildivpow2(l_comp_y1, l_img_comp->factor) - - int_ceildivpow2(l_img_comp->y0, l_img_comp->factor); - if (l_h < 0){ - opj_event_msg_v2(p_manager, EVT_ERROR, - "Size y of the decoded component image is incorrect (comp[%d].h=%d).\n", - it_comp, l_h); - return OPJ_FALSE; + /* quantization style*/ + l_tccp_info->qntsty = l_tccp->qntsty; + l_tccp_info->numgbits = l_tccp->numgbits; + + numbands = (l_tccp->qntsty == J2K_CCP_QNTSTY_SIQNT) ? 1 : l_tccp->numresolutions * 3 - 2; + if (numbands < J2K_MAXBANDS) { + for (bandno = 0; bandno < numbands; bandno++) { + l_tccp_info->stepsizes_mant[bandno] = l_tccp->stepsizes[bandno].mant; + l_tccp_info->stepsizes_expn[bandno] = l_tccp->stepsizes[bandno].expn; + } } - l_img_comp->h = l_h; - l_img_comp++; + /* RGN value*/ + l_tccp_info->roishift = l_tccp->roishift; } - opj_event_msg_v2( p_manager, EVT_INFO,"Setting decoding area to %d,%d,%d,%d\n", - p_image->x0, p_image->y0, p_image->x1, p_image->y1); - - return OPJ_TRUE; + return cstr_info; } - -/* ----------------------------------------------------------------------- */ -/* J2K / JPT decoder interface */ -/* ----------------------------------------------------------------------- */ /** - * Creates a J2K decompression structure. + * Get the codestream index from a JPEG2000 codec. * - * @return a handle to a J2K decompressor if successful, NULL otherwise. -*/ -opj_j2k_v2_t* j2k_create_decompress_v2() + *@param p_j2k the component image header to dump. + * + *@return the codestream index extract from the jpg2000 codec + */ +opj_codestream_index_t* j2k_get_cstr_index(opj_j2k_v2_t* p_j2k) { - opj_j2k_v2_t *l_j2k = (opj_j2k_v2_t*) opj_malloc(sizeof(opj_j2k_v2_t)); - if (!l_j2k) { - return 00; - } - memset(l_j2k,0,sizeof(opj_j2k_v2_t)); + opj_codestream_index_t* l_cstr_index = (opj_codestream_index_t*) + opj_calloc(1,sizeof(opj_codestream_index_t)); + if (!l_cstr_index) + return NULL; - l_j2k->m_is_decoder = 1; - l_j2k->m_cp.m_is_decoder = 1; + l_cstr_index->main_head_start = p_j2k->cstr_index->main_head_start; + l_cstr_index->main_head_end = p_j2k->cstr_index->main_head_end; + l_cstr_index->codestream_size = p_j2k->cstr_index->codestream_size; - l_j2k->m_specific_param.m_decoder.m_default_tcp = (opj_tcp_v2_t*) opj_malloc(sizeof(opj_tcp_v2_t)); - if (!l_j2k->m_specific_param.m_decoder.m_default_tcp) { - j2k_destroy(l_j2k); - return 00; + l_cstr_index->marknum = p_j2k->cstr_index->marknum; + l_cstr_index->marker = (opj_marker_info_t*)opj_malloc(l_cstr_index->marknum*sizeof(opj_marker_info_t)); + if (!l_cstr_index->marker){ + opj_free( l_cstr_index); + return NULL; } - memset(l_j2k->m_specific_param.m_decoder.m_default_tcp,0,sizeof(opj_tcp_v2_t)); - l_j2k->m_specific_param.m_decoder.m_header_data = (OPJ_BYTE *) opj_malloc(J2K_DEFAULT_HEADER_SIZE); - if (! l_j2k->m_specific_param.m_decoder.m_header_data) { - j2k_destroy(l_j2k); - return 00; + if (p_j2k->cstr_index->marker) + memcpy(l_cstr_index->marker, p_j2k->cstr_index->marker, l_cstr_index->marknum * sizeof(opj_marker_info_t) ); + else{ + opj_free(l_cstr_index->marker); + l_cstr_index->marker = NULL; } - l_j2k->m_specific_param.m_decoder.m_header_data_size = J2K_DEFAULT_HEADER_SIZE; - - l_j2k->m_specific_param.m_decoder.m_tile_ind_to_dec = -1 ; - - l_j2k->m_specific_param.m_decoder.m_last_sot_read_pos = 0 ; - - /* codestream index creation */ - l_j2k->cstr_index = j2k_create_cstr_index(); - - /*(opj_codestream_index_t*) opj_malloc(sizeof(opj_codestream_index_t)); - if (!l_j2k->cstr_index){ - j2k_destroy(l_j2k); + l_cstr_index->nb_of_tiles = p_j2k->cstr_index->nb_of_tiles; + l_cstr_index->tile_index = (opj_tile_index_t*)opj_calloc(l_cstr_index->nb_of_tiles, sizeof(opj_tile_index_t) ); + if (!l_cstr_index->tile_index){ + opj_free( l_cstr_index->marker); + opj_free( l_cstr_index); return NULL; } - l_j2k->cstr_index->marker = (opj_marker_info_t*) opj_malloc(100 * sizeof(opj_marker_info_t)); -*/ - - /* validation list creation */ - l_j2k->m_validation_list = opj_procedure_list_create(); - if (! l_j2k->m_validation_list) { - j2k_destroy(l_j2k); - return 00; + if (!p_j2k->cstr_index->tile_index){ + opj_free(l_cstr_index->tile_index); + l_cstr_index->tile_index = NULL; } + else { + OPJ_UINT32 it_tile = 0; + for (it_tile = 0; it_tile < l_cstr_index->nb_of_tiles; it_tile++ ){ - /* execution list creation */ - l_j2k->m_procedure_list = opj_procedure_list_create(); - if (! l_j2k->m_procedure_list) { - j2k_destroy(l_j2k); - return 00; - } + /* Tile Marker*/ + l_cstr_index->tile_index[it_tile].marknum = p_j2k->cstr_index->tile_index[it_tile].marknum; - return l_j2k; -} + l_cstr_index->tile_index[it_tile].marker = + (opj_marker_info_t*)opj_malloc(l_cstr_index->tile_index[it_tile].marknum*sizeof(opj_marker_info_t)); + if (!l_cstr_index->tile_index[it_tile].marker) { + OPJ_UINT32 it_tile_free; -opj_codestream_index_t* j2k_create_cstr_index(void) -{ - opj_codestream_index_t* cstr_index = (opj_codestream_index_t*) - opj_calloc(1,sizeof(opj_codestream_index_t)); - if (!cstr_index) - return NULL; + for (it_tile_free=0; it_tile_free < it_tile; it_tile_free++){ + opj_free(l_cstr_index->tile_index[it_tile_free].marker); + } - cstr_index->maxmarknum = 100; - cstr_index->marknum = 0; - cstr_index->marker = (opj_marker_info_t*) - opj_calloc(cstr_index->maxmarknum, sizeof(opj_marker_info_t)); - if (!cstr_index-> marker) - return NULL; + opj_free( l_cstr_index->tile_index); + opj_free( l_cstr_index->marker); + opj_free( l_cstr_index); + return NULL; + } - cstr_index->tile_index = NULL; + if (p_j2k->cstr_index->tile_index[it_tile].marker) + memcpy( l_cstr_index->tile_index[it_tile].marker, + p_j2k->cstr_index->tile_index[it_tile].marker, + l_cstr_index->tile_index[it_tile].marknum * sizeof(opj_marker_info_t) ); + else{ + opj_free(l_cstr_index->tile_index[it_tile].marker); + l_cstr_index->tile_index[it_tile].marker = NULL; + } - return cstr_index; -} + /* Tile part index*/ + l_cstr_index->tile_index[it_tile].nb_tps = p_j2k->cstr_index->tile_index[it_tile].nb_tps; -/** - * Reads a SPCod or SPCoc element, i.e. the coding style of a given component of a tile. - * @param p_header_data the data contained in the COM box. - * @param p_j2k the jpeg2000 codec. - * @param p_header_size the size of the data contained in the COM marker. - * @param p_manager the user event manager. -*/ -opj_bool j2k_read_SPCod_SPCoc( - opj_j2k_v2_t *p_j2k, - OPJ_UINT32 compno, - OPJ_BYTE * p_header_data, - OPJ_UINT32 * p_header_size, - struct opj_event_mgr * p_manager - ) -{ - OPJ_UINT32 i, l_tmp; - opj_cp_v2_t *l_cp = NULL; - opj_tcp_v2_t *l_tcp = NULL; - opj_tccp_t *l_tccp = NULL; - OPJ_BYTE * l_current_ptr = NULL; + l_cstr_index->tile_index[it_tile].tp_index = + (opj_tp_index_t*)opj_malloc(l_cstr_index->tile_index[it_tile].nb_tps*sizeof(opj_tp_index_t)); - /* preconditions */ - assert(p_j2k != 00); - assert(p_manager != 00); - assert(p_header_data != 00); + if(!l_cstr_index->tile_index[it_tile].tp_index){ + OPJ_UINT32 it_tile_free; - l_cp = &(p_j2k->m_cp); - l_tcp = (p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_TPH) ? - &l_cp->tcps[p_j2k->m_current_tile_number] : - p_j2k->m_specific_param.m_decoder.m_default_tcp; + for (it_tile_free=0; it_tile_free < it_tile; it_tile_free++){ + opj_free(l_cstr_index->tile_index[it_tile_free].marker); + opj_free(l_cstr_index->tile_index[it_tile_free].tp_index); + } - /* precondition again */ - assert(compno < p_j2k->m_private_image->numcomps); + opj_free( l_cstr_index->tile_index); + opj_free( l_cstr_index->marker); + opj_free( l_cstr_index); + return NULL; + } - l_tccp = &l_tcp->tccps[compno]; - l_current_ptr = p_header_data; + if (p_j2k->cstr_index->tile_index[it_tile].tp_index){ + memcpy( l_cstr_index->tile_index[it_tile].tp_index, + p_j2k->cstr_index->tile_index[it_tile].tp_index, + l_cstr_index->tile_index[it_tile].nb_tps * sizeof(opj_tp_index_t) ); + } + else{ + opj_free(l_cstr_index->tile_index[it_tile].tp_index); + l_cstr_index->tile_index[it_tile].tp_index = NULL; + } - /* make sure room is sufficient */ - if (*p_header_size < 5) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading SPCod SPCoc element\n"); - return OPJ_FALSE; + /* Packet index (NOT USED)*/ + l_cstr_index->tile_index[it_tile].nb_packet = 0; + l_cstr_index->tile_index[it_tile].packet_index = NULL; + + } } - opj_read_bytes(l_current_ptr, &l_tccp->numresolutions ,1); /* SPcox (D) */ - ++l_tccp->numresolutions; /* tccp->numresolutions = read() + 1 */ - ++l_current_ptr; + return l_cstr_index; +} - /* 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_v2(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); - p_j2k->m_specific_param.m_decoder.m_state |= 0x8000;// FIXME J2K_DEC_STATE_ERR; +static opj_bool j2k_allocate_tile_element_cstr_index(opj_j2k_v2_t *p_j2k) +{ + OPJ_UINT32 it_tile=0; + + p_j2k->cstr_index->nb_of_tiles = p_j2k->m_cp.tw * p_j2k->m_cp.th; + p_j2k->cstr_index->tile_index = (opj_tile_index_t*)opj_calloc(p_j2k->cstr_index->nb_of_tiles, sizeof(opj_tile_index_t)); + if (!p_j2k->cstr_index->tile_index) return OPJ_FALSE; + + for (it_tile=0; it_tile < p_j2k->cstr_index->nb_of_tiles; it_tile++){ + p_j2k->cstr_index->tile_index[it_tile].maxmarknum = 100; + p_j2k->cstr_index->tile_index[it_tile].marknum = 0; + p_j2k->cstr_index->tile_index[it_tile].marker = (opj_marker_info_t*) + opj_calloc(p_j2k->cstr_index->tile_index[it_tile].maxmarknum, sizeof(opj_marker_info_t)); + if (!p_j2k->cstr_index->tile_index[it_tile].marker) + return OPJ_FALSE; } - opj_read_bytes(l_current_ptr,&l_tccp->cblkw ,1); /* SPcoc (E) */ - ++l_current_ptr; - l_tccp->cblkw += 2; + return OPJ_TRUE; +} - opj_read_bytes(l_current_ptr,&l_tccp->cblkh ,1); /* SPcoc (F) */ - ++l_current_ptr; - l_tccp->cblkh += 2; +/** + * Reads the tiles. + */ +opj_bool j2k_decode_tiles ( opj_j2k_v2_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_read_bytes(l_current_ptr,&l_tccp->cblksty ,1); /* SPcoc (G) */ - ++l_current_ptr; + l_current_data = (OPJ_BYTE*)opj_malloc(1000); + if (! l_current_data) { + return OPJ_FALSE; + } + l_max_data_size = 1000; - opj_read_bytes(l_current_ptr,&l_tccp->qmfbid ,1); /* SPcoc (H) */ - ++l_current_ptr; - *p_header_size = *p_header_size - 5; - /* use custom precinct size ? */ - if (l_tccp->csty & J2K_CCP_CSTY_PRT) { - if (*p_header_size < l_tccp->numresolutions) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading SPCod SPCoc element\n"); + while (OPJ_TRUE) { + if (! 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; } - for (i = 0; i < l_tccp->numresolutions; ++i) { - opj_read_bytes(l_current_ptr,&l_tmp ,1); /* SPcoc (I_i) */ - ++l_current_ptr; - l_tccp->prcw[i] = l_tmp & 0xf; - l_tccp->prch[i] = l_tmp >> 4; + if (! l_go_on) { + break; } - *p_header_size = *p_header_size - l_tccp->numresolutions; - } - else { - /* set default size for the precinct width and height */ - for (i = 0; i < l_tccp->numresolutions; ++i) { - l_tccp->prcw[i] = 15; - l_tccp->prch[i] = 15; - } - } + if (l_data_size > l_max_data_size) { + l_current_data = (OPJ_BYTE*)opj_realloc(l_current_data,l_data_size); + if (! l_current_data) { + opj_free(l_current_data); + return OPJ_FALSE; + } -#ifdef WIP_REMOVE_MSD - /* INDEX >> */ - if (p_j2k->cstr_info && compno == 0) { - OPJ_UINT32 l_data_size = l_tccp->numresolutions * sizeof(OPJ_UINT32); + l_max_data_size = l_data_size; + } - p_j2k->cstr_info->tile[p_j2k->m_current_tile_number].tccp_info[compno].cblkh = l_tccp->cblkh; - p_j2k->cstr_info->tile[p_j2k->m_current_tile_number].tccp_info[compno].cblkw = l_tccp->cblkw; - p_j2k->cstr_info->tile[p_j2k->m_current_tile_number].tccp_info[compno].numresolutions = l_tccp->numresolutions; - p_j2k->cstr_info->tile[p_j2k->m_current_tile_number].tccp_info[compno].cblksty = l_tccp->cblksty; - p_j2k->cstr_info->tile[p_j2k->m_current_tile_number].tccp_info[compno].qmfbid = l_tccp->qmfbid; + if (! j2k_decode_tile(p_j2k,l_current_tile_no,l_current_data,l_data_size,p_stream,p_manager)) { + opj_free(l_current_data); + return OPJ_FALSE; + } + opj_event_msg_v2(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 (! j2k_update_image_data(p_j2k->m_tcd,l_current_data, p_j2k->m_output_image)) { + opj_free(l_current_data); + return OPJ_FALSE; + } + opj_event_msg_v2(p_manager, EVT_INFO, "Image data has been updated with tile %d.\n\n", l_current_tile_no + 1); - memcpy(p_j2k->cstr_info->tile[p_j2k->m_current_tile_number].pdx,l_tccp->prcw, l_data_size); - memcpy(p_j2k->cstr_info->tile[p_j2k->m_current_tile_number].pdy,l_tccp->prch, l_data_size); } - /* << INDEX */ -#endif + + opj_free(l_current_data); return OPJ_TRUE; } /** - * Copies the tile component parameters of all the component from the first tile component. - * - * @param p_j2k the J2k codec. + * Sets up the procedures to do on decoding data. Developpers wanting to extend the library can add their own reading procedures. */ -void j2k_copy_tile_component_parameters( opj_j2k_v2_t *p_j2k ) +static void j2k_setup_decoding (opj_j2k_v2_t *p_j2k) { - // loop - OPJ_UINT32 i; - opj_cp_v2_t *l_cp = NULL; - opj_tcp_v2_t *l_tcp = NULL; - opj_tccp_t *l_ref_tccp = NULL, *l_copied_tccp = NULL; - OPJ_UINT32 l_prc_size; - - /* preconditions */ + /* preconditions*/ assert(p_j2k != 00); - l_cp = &(p_j2k->m_cp); - l_tcp = (p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_TPH) ? /* FIXME J2K_DEC_STATE_TPH*/ - &l_cp->tcps[p_j2k->m_current_tile_number] : - p_j2k->m_specific_param.m_decoder.m_default_tcp; - - l_ref_tccp = &l_tcp->tccps[0]; - l_copied_tccp = l_ref_tccp + 1; - l_prc_size = l_ref_tccp->numresolutions * sizeof(OPJ_UINT32); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)j2k_decode_tiles); + /* DEVELOPER CORNER, add your custom procedures */ - for (i=1; im_private_image->numcomps; ++i) { - l_copied_tccp->numresolutions = l_ref_tccp->numresolutions; - l_copied_tccp->cblkw = l_ref_tccp->cblkw; - l_copied_tccp->cblkh = l_ref_tccp->cblkh; - l_copied_tccp->cblksty = l_ref_tccp->cblksty; - l_copied_tccp->qmfbid = l_ref_tccp->qmfbid; - memcpy(l_copied_tccp->prcw,l_ref_tccp->prcw,l_prc_size); - memcpy(l_copied_tccp->prch,l_ref_tccp->prch,l_prc_size); - ++l_copied_tccp; - } } -/** - * Reads a SQcd or SQcc element, i.e. the quantization values of a band. - * - * @param p_comp_no the component being targeted. - * @param p_header_data the data contained in the COM box. - * @param p_j2k the jpeg2000 codec. - * @param p_header_size the size of the data contained in the COM marker. - * @param p_manager the user event manager. -*/ -opj_bool j2k_read_SQcd_SQcc( - opj_j2k_v2_t *p_j2k, - OPJ_UINT32 p_comp_no, - OPJ_BYTE* p_header_data, - OPJ_UINT32 * p_header_size, - struct opj_event_mgr * p_manager - ) +/* + * Read and decode one tile. + */ +static opj_bool j2k_decode_one_tile ( opj_j2k_v2_t *p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager) { - // loop - OPJ_UINT32 l_band_no; - opj_cp_v2_t *l_cp = 00; - opj_tcp_v2_t *l_tcp = 00; - opj_tccp_t *l_tccp = 00; - OPJ_BYTE * l_current_ptr = 00; - OPJ_UINT32 l_tmp, l_num_band; - - // preconditions - assert(p_j2k != 00); - assert(p_manager != 00); - assert(p_header_data != 00); - - l_cp = &(p_j2k->m_cp); - // come from tile part header or main header ? - l_tcp = (p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_TPH) ? /*FIXME J2K_DEC_STATE_TPH*/ - &l_cp->tcps[p_j2k->m_current_tile_number] : - p_j2k->m_specific_param.m_decoder.m_default_tcp; - - // precondition again - assert(p_comp_no < p_j2k->m_private_image->numcomps); - - l_tccp = &l_tcp->tccps[p_comp_no]; - l_current_ptr = p_header_data; + 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; - if (*p_header_size < 1) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading SQcd or SQcc element\n"); + l_current_data = (OPJ_BYTE*)opj_malloc(1000); + if (! l_current_data) { return OPJ_FALSE; } - *p_header_size -= 1; - - opj_read_bytes(l_current_ptr, &l_tmp ,1); /* Sqcx */ - ++l_current_ptr; + l_max_data_size = 1000; - l_tccp->qntsty = l_tmp & 0x1f; - l_tccp->numgbits = l_tmp >> 5; - if (l_tccp->qntsty == J2K_CCP_QNTSTY_SIQNT) { - l_num_band = 1; + /*Allocate and initialize some elements of codestrem index if not already done*/ + if( !p_j2k->cstr_index->tile_index) + { + if (!j2k_allocate_tile_element_cstr_index(p_j2k)){ + opj_free(l_current_data); + return OPJ_FALSE; + } } - else { - l_num_band = (l_tccp->qntsty == J2K_CCP_QNTSTY_NOQNT) ? - (*p_header_size) : - (*p_header_size) / 2; + /* Move into the codestream to the first SOT used to decode the desired tile */ + l_tile_no_to_dec = p_j2k->m_specific_param.m_decoder.m_tile_ind_to_dec; + if (p_j2k->cstr_index->tile_index) + if(p_j2k->cstr_index->tile_index->tp_index) + { + if ( ! p_j2k->cstr_index->tile_index[l_tile_no_to_dec].nb_tps) { + /* the index for this tile has not been built, + * so move to the last SOT read */ + 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_v2(p_manager, EVT_ERROR, "Problem with seek function\n"); + return OPJ_FALSE; + } + } + else{ + if (opj_stream_read_seek(p_stream, p_j2k->cstr_index->tile_index[l_tile_no_to_dec].tp_index[0].start_pos+2, p_manager)) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Problem with seek function\n"); + return OPJ_FALSE; + } + } + /* Special case if we have previously read the EOC marker (if the previous tile getted is the last ) */ + if(p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_EOC) + p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_TPHSOT; + } - if( l_num_band > J2K_MAXBANDS ) { - opj_event_msg_v2(p_manager, EVT_WARNING, "While reading CCP_QNTSTY element inside QCD or QCC marker segment, " - "number of subbands (%d) is greater to J2K_MAXBANDS (%d). So we limiting the number of elements stored to " - "J2K_MAXBANDS (%d) and skip the other. \n", l_num_band, J2K_MAXBANDS, J2K_MAXBANDS); - //return OPJ_FALSE; + while (OPJ_TRUE) { + if (! 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; } - } -#ifdef USE_JPWL - if (l_cp->correct) { - /* if JPWL is on, we check whether there are too many subbands */ - if ((l_num_band < 0) || (l_num_band >= J2K_MAXBANDS)) { - opj_event_msg_v2(p_manager, JPWL_ASSUME ? EVT_WARNING : EVT_ERROR, - "JPWL: bad number of subbands in Sqcx (%d)\n", - l_num_band); - if (!JPWL_ASSUME) { - opj_event_msg_v2(p_manager, EVT_ERROR, "JPWL: giving up\n"); + if (! l_go_on) { + break; + } + + if (l_data_size > l_max_data_size) { + l_current_data = (OPJ_BYTE*)opj_realloc(l_current_data,l_data_size); + if (! l_current_data) { + opj_free(l_current_data); return OPJ_FALSE; } - /* we try to correct */ - l_num_band = 1; - opj_event_msg_v2(p_manager, EVT_WARNING, "- trying to adjust them\n" - "- setting number of bands to %d => HYPOTHESIS!!!\n", - l_num_band); - }; - }; -#endif /* USE_JPWL */ + l_max_data_size = l_data_size; + } - if (l_tccp->qntsty == J2K_CCP_QNTSTY_NOQNT) { - for (l_band_no = 0; l_band_no < l_num_band; l_band_no++) { - opj_read_bytes(l_current_ptr, &l_tmp ,1); /* SPqcx_i */ - ++l_current_ptr; - if (l_band_no < J2K_MAXBANDS){ - l_tccp->stepsizes[l_band_no].expn = l_tmp>>3; - l_tccp->stepsizes[l_band_no].mant = 0; - } + + + if (! j2k_decode_tile(p_j2k,l_current_tile_no,l_current_data,l_data_size,p_stream,p_manager)) { + opj_free(l_current_data); + return OPJ_FALSE; } - *p_header_size = *p_header_size - l_num_band; - } - else { - for (l_band_no = 0; l_band_no < l_num_band; l_band_no++) { - opj_read_bytes(l_current_ptr, &l_tmp ,2); /* SPqcx_i */ - l_current_ptr+=2; - if (l_band_no < J2K_MAXBANDS){ - l_tccp->stepsizes[l_band_no].expn = l_tmp >> 11; - l_tccp->stepsizes[l_band_no].mant = l_tmp & 0x7ff; + opj_event_msg_v2(p_manager, EVT_INFO, "Tile %d/%d has been decoded.\n", l_current_tile_no, (p_j2k->m_cp.th * p_j2k->m_cp.tw) - 1); + + if (! j2k_update_image_data(p_j2k->m_tcd,l_current_data, p_j2k->m_output_image)) { + opj_free(l_current_data); + return OPJ_FALSE; + } + opj_event_msg_v2(p_manager, EVT_INFO, "Image data has been updated with tile %d.\n\n", l_current_tile_no); + + if(l_current_tile_no == l_tile_no_to_dec) + { + /* move into the codestream to the the first SOT (FIXME or not move?)*/ + if (!(opj_stream_read_seek(p_stream, p_j2k->cstr_index->main_head_end + 2, p_manager) ) ) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Problem with seek function\n"); + return OPJ_FALSE; } + break; + } + else { + opj_event_msg_v2(p_manager, EVT_WARNING, "Tile read, decode and updated is not the desired (%d vs %d).\n", l_current_tile_no, l_tile_no_to_dec); } - *p_header_size = *p_header_size - 2*l_num_band; - } - /* Add Antonin : if scalar_derived -> compute other stepsizes */ - if (l_tccp->qntsty == J2K_CCP_QNTSTY_SIQNT) { - for (l_band_no = 1; l_band_no < J2K_MAXBANDS; l_band_no++) { - l_tccp->stepsizes[l_band_no].expn = - ((l_tccp->stepsizes[0].expn) - ((l_band_no - 1) / 3) > 0) ? - (l_tccp->stepsizes[0].expn) - ((l_band_no - 1) / 3) : 0; - l_tccp->stepsizes[l_band_no].mant = l_tccp->stepsizes[0].mant; - } } + opj_free(l_current_data); + return OPJ_TRUE; } + /** - * Copies the tile component parameters of all the component from the first tile component. - * - * @param p_j2k the J2k codec. + * Sets up the procedures to do on decoding one tile. Developpers wanting to extend the library can add their own reading procedures. */ -void j2k_copy_tile_quantization_parameters( opj_j2k_v2_t *p_j2k ) +static void j2k_setup_decoding_tile (opj_j2k_v2_t *p_j2k) { - OPJ_UINT32 i; - opj_cp_v2_t *l_cp = NULL; - opj_tcp_v2_t *l_tcp = NULL; - opj_tccp_t *l_ref_tccp = NULL; - opj_tccp_t *l_copied_tccp = NULL; - OPJ_UINT32 l_size; - - /* preconditions */ + /* preconditions*/ assert(p_j2k != 00); - l_cp = &(p_j2k->m_cp); - l_tcp = p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_TPH ? - &l_cp->tcps[p_j2k->m_current_tile_number] : - p_j2k->m_specific_param.m_decoder.m_default_tcp; - - l_ref_tccp = &l_tcp->tccps[0]; - l_copied_tccp = l_ref_tccp + 1; - l_size = J2K_MAXBANDS * sizeof(opj_stepsize_t); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)j2k_decode_one_tile); + /* DEVELOPER CORNER, add your custom procedures */ - for (i=1;im_private_image->numcomps;++i) { - l_copied_tccp->qntsty = l_ref_tccp->qntsty; - l_copied_tccp->numgbits = l_ref_tccp->numgbits; - memcpy(l_copied_tccp->stepsizes,l_ref_tccp->stepsizes,l_size); - ++l_copied_tccp; - } } + /** - * Dump some elements from the J2K decompression structure . - * - *@param p_j2k the jpeg2000 codec. - *@param flag flag to describe what elments are dump. - *@param out_stream output stream where dump the elements. - * -*/ -void j2k_dump (opj_j2k_v2_t* p_j2k, OPJ_INT32 flag, FILE* out_stream) + * Decodes the tiles of the stream. + */ +opj_bool j2k_decode_v2( opj_j2k_v2_t * p_j2k, + opj_stream_private_t * p_stream, + opj_image_t * p_image, + opj_event_mgr_t * p_manager) { - /* Check if the flag is compatible with j2k file*/ - if ( (flag & OPJ_JP2_INFO) || (flag & OPJ_JP2_IND)){ - fprintf(out_stream, "Wrong flag\n"); - return; - } + OPJ_UINT32 compno; - /* Dump the image_header */ - if (flag & OPJ_IMG_INFO){ - if (p_j2k->m_private_image) - j2k_dump_image_header(p_j2k->m_private_image, 0, out_stream); - } + if (!p_image) + return OPJ_FALSE; - /* Dump the codestream info from main header */ - if (flag & OPJ_J2K_MH_INFO){ - j2k_dump_MH_info(p_j2k, out_stream); + 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); + /* customization of the decoding */ + j2k_setup_decoding(p_j2k); - /* Dump the codestream info of the current tile */ - if (flag & OPJ_J2K_TH_INFO){ - - } - - /* Dump the codestream index from main header */ - if (flag & OPJ_J2K_MH_IND){ - j2k_dump_MH_index(p_j2k, out_stream); + /* Decode the codestream */ + if (! j2k_exec (p_j2k,p_j2k->m_procedure_list,p_stream,p_manager)) { + opj_image_destroy(p_j2k->m_private_image); + p_j2k->m_private_image = NULL; + return OPJ_FALSE; } - /* Dump the codestream index of the current tile */ - if (flag & OPJ_J2K_TH_IND){ - + /* 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; + p_j2k->m_output_image->comps[compno].data = NULL; } + return OPJ_TRUE; } + /** - * Dump index elements of the codestream extract from the main header. + * Get the decoded tile. * - *@param p_j2k the jpeg2000 codec. - *@param out_stream output stream where dump the elements. + * @param p_j2k the jpeg2000 codestream codec. + * @param p_stream input_stream + * @param p_image output image. . + * @param p_manager the user event manager + * @param tile_index index of the tile we want decode * -*/ -void j2k_dump_MH_index(opj_j2k_v2_t* p_j2k, FILE* out_stream) + * @return true if succeed. + */ +opj_bool j2k_get_tile( opj_j2k_v2_t *p_j2k, + opj_stream_private_t *p_stream, + opj_image_t* p_image, + struct opj_event_mgr * p_manager, + OPJ_UINT32 tile_index ) { - opj_codestream_index_t* cstr_index = p_j2k->cstr_index; - OPJ_UINT32 it_marker, it_tile, it_tile_part; - - fprintf(out_stream, "Codestream index from main header: {\n"); - - fprintf(out_stream, "\t Main header start position=%d\n\t Main header end position=%d\n", - cstr_index->main_head_start, cstr_index->main_head_end); - - fprintf(out_stream, "\t Marker list: {\n"); + OPJ_UINT32 compno; + OPJ_UINT32 l_tile_x, l_tile_y; + opj_image_comp_t* l_img_comp; - if (cstr_index->marker){ - for (it_marker=0; it_marker < cstr_index->marknum ; it_marker++){ - fprintf(out_stream, "\t\t type=%#x, pos=%d, len=%d\n", - cstr_index->marker[it_marker].type, - cstr_index->marker[it_marker].pos, - cstr_index->marker[it_marker].len ); - } + if (!p_image) { + opj_event_msg_v2(p_manager, EVT_ERROR, "We need an image previously created.\n"); + return OPJ_FALSE; } - fprintf(out_stream, "\t }\n"); - - - if (cstr_index->tile_index){ - fprintf(out_stream, "\t Tile index: {\n"); - - for (it_tile=0; it_tile < cstr_index->nb_of_tiles ; it_tile++){ - OPJ_UINT32 nb_of_tile_part = cstr_index->tile_index[it_tile].nb_tps; + if ( /*(tile_index < 0) &&*/ (tile_index >= p_j2k->m_cp.tw * p_j2k->m_cp.th) ){ + opj_event_msg_v2(p_manager, EVT_ERROR, "Tile index provided by the user is incorrect %d (max = %d) \n", tile_index, (p_j2k->m_cp.tw * p_j2k->m_cp.th) - 1); + return OPJ_FALSE; + } - fprintf(out_stream, "\t\t nb of tile-part in tile [%d]=%d\n", it_tile, nb_of_tile_part); + /* Compute the dimension of the desired tile*/ + l_tile_x = tile_index % p_j2k->m_cp.tw; + l_tile_y = tile_index / p_j2k->m_cp.tw; - if (cstr_index->tile_index[it_tile].tp_index){ - for (it_tile_part =0; it_tile_part < nb_of_tile_part; it_tile_part++){ - fprintf(out_stream, "\t\t\t tile-part[%d]: star_pos=%d, end_header=%d, end_pos=%d.\n", - it_tile_part, - cstr_index->tile_index[it_tile].tp_index[it_tile_part].start_pos, - cstr_index->tile_index[it_tile].tp_index[it_tile_part].end_header, - cstr_index->tile_index[it_tile].tp_index[it_tile_part].end_pos); - } - } + p_image->x0 = l_tile_x * p_j2k->m_cp.tdx + p_j2k->m_cp.tx0; + if (p_image->x0 < p_j2k->m_private_image->x0) + p_image->x0 = p_j2k->m_private_image->x0; + p_image->x1 = (l_tile_x + 1) * p_j2k->m_cp.tdx + p_j2k->m_cp.tx0; + if (p_image->x1 > p_j2k->m_private_image->x1) + p_image->x1 = p_j2k->m_private_image->x1; - if (cstr_index->tile_index[it_tile].marker){ - for (it_marker=0; it_marker < cstr_index->tile_index[it_tile].marknum ; it_marker++){ - fprintf(out_stream, "\t\t type=%#x, pos=%d, len=%d\n", - cstr_index->tile_index[it_tile].marker[it_marker].type, - cstr_index->tile_index[it_tile].marker[it_marker].pos, - cstr_index->tile_index[it_tile].marker[it_marker].len ); - } - } - } - fprintf(out_stream,"\t }\n"); - } + p_image->y0 = l_tile_y * p_j2k->m_cp.tdy + p_j2k->m_cp.ty0; + if (p_image->y0 < p_j2k->m_private_image->y0) + p_image->y0 = p_j2k->m_private_image->y0; + p_image->y1 = (l_tile_y + 1) * p_j2k->m_cp.tdy + p_j2k->m_cp.ty0; + if (p_image->y1 > p_j2k->m_private_image->y1) + p_image->y1 = p_j2k->m_private_image->y1; - fprintf(out_stream,"}\n"); + l_img_comp = p_image->comps; + for (compno=0; compno < p_image->numcomps; ++compno) + { + OPJ_INT32 l_comp_x1, l_comp_y1; -} + l_img_comp->factor = p_j2k->m_private_image->comps[compno].factor; -/** - * Dump info elements of the codestream extract from the main header. - * - *@param p_j2k the jpeg2000 codec. - *@param out_stream output stream where dump the elements. - * -*/ -void j2k_dump_MH_info(opj_j2k_v2_t* p_j2k, FILE* out_stream) -{ - opj_tcp_v2_t * l_default_tile=NULL; + l_img_comp->x0 = int_ceildiv(p_image->x0, l_img_comp->dx); + l_img_comp->y0 = int_ceildiv(p_image->y0, l_img_comp->dy); + l_comp_x1 = int_ceildiv(p_image->x1, l_img_comp->dx); + l_comp_y1 = int_ceildiv(p_image->y1, l_img_comp->dy); - fprintf(out_stream, "Codestream info from main header: {\n"); + l_img_comp->w = int_ceildivpow2(l_comp_x1, l_img_comp->factor) - int_ceildivpow2(l_img_comp->x0, l_img_comp->factor); + l_img_comp->h = int_ceildivpow2(l_comp_y1, l_img_comp->factor) - int_ceildivpow2(l_img_comp->y0, l_img_comp->factor); - fprintf(out_stream, "\t tx0=%d, ty0=%d\n", p_j2k->m_cp.tx0, p_j2k->m_cp.ty0); - fprintf(out_stream, "\t tdx=%d, tdy=%d\n", p_j2k->m_cp.tdx, p_j2k->m_cp.tdy); - fprintf(out_stream, "\t tw=%d, th=%d\n", p_j2k->m_cp.tw, p_j2k->m_cp.th); + l_img_comp++; + } - l_default_tile = p_j2k->m_specific_param.m_decoder.m_default_tcp; - if (l_default_tile) - { - OPJ_INT32 compno; - OPJ_INT32 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); - fprintf(out_stream, "\t default tile {\n"); - fprintf(out_stream, "\t\t csty=%#x\n", l_default_tile->csty); - fprintf(out_stream, "\t\t prg=%#x\n", l_default_tile->prg); - fprintf(out_stream, "\t\t numlayers=%d\n", l_default_tile->numlayers); - fprintf(out_stream, "\t\t mct=%x\n", l_default_tile->mct); + /* Create the ouput image from the information previously computed*/ + 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); - for (compno = 0; compno < numcomps; compno++) { - opj_tccp_t *l_tccp = &(l_default_tile->tccps[compno]); - OPJ_INT32 resno, bandno, numbands; + p_j2k->m_specific_param.m_decoder.m_tile_ind_to_dec = tile_index; - /* coding style*/ - fprintf(out_stream, "\t\t comp %d {\n", compno); - fprintf(out_stream, "\t\t\t csty=%#x\n", l_tccp->csty); - fprintf(out_stream, "\t\t\t numresolutions=%d\n", l_tccp->numresolutions); - fprintf(out_stream, "\t\t\t cblkw=2^%d\n", l_tccp->cblkw); - fprintf(out_stream, "\t\t\t cblkh=2^%d\n", l_tccp->cblkh); - fprintf(out_stream, "\t\t\t cblksty=%#x\n", l_tccp->cblksty); - fprintf(out_stream, "\t\t\t qmfbid=%d\n", l_tccp->qmfbid); + /* customization of the decoding */ + j2k_setup_decoding_tile(p_j2k); - fprintf(out_stream, "\t\t\t preccintsize (w,h)="); - for (resno = 0; resno < l_tccp->numresolutions; resno++) { - fprintf(out_stream, "(%d,%d) ", l_tccp->prcw[resno], l_tccp->prch[resno]); - } - fprintf(out_stream, "\n"); + /* Decode the codestream */ + if (! j2k_exec (p_j2k,p_j2k->m_procedure_list,p_stream,p_manager)) { + opj_image_destroy(p_j2k->m_private_image); + p_j2k->m_private_image = NULL; + return OPJ_FALSE; + } - /* quantization style*/ - fprintf(out_stream, "\t\t\t qntsty=%d\n", l_tccp->qntsty); - fprintf(out_stream, "\t\t\t numgbits=%d\n", l_tccp->numgbits); - fprintf(out_stream, "\t\t\t stepsizes (m,e)="); - numbands = (l_tccp->qntsty == J2K_CCP_QNTSTY_SIQNT) ? 1 : l_tccp->numresolutions * 3 - 2; - for (bandno = 0; bandno < numbands; bandno++) { - fprintf(out_stream, "(%d,%d) ", l_tccp->stepsizes[bandno].mant, - l_tccp->stepsizes[bandno].expn); - } - fprintf(out_stream, "\n"); + /* 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; - /* RGN value*/ - fprintf(out_stream, "\t\t\t roishift=%d\n", l_tccp->roishift); + if (p_image->comps[compno].data) + opj_free(p_image->comps[compno].data); - fprintf(out_stream, "\t\t }\n"); - } /*end of component of default tile*/ - fprintf(out_stream, "\t }\n"); /*end of default tile*/ + p_image->comps[compno].data = p_j2k->m_output_image->comps[compno].data; + p_j2k->m_output_image->comps[compno].data = NULL; } - fprintf(out_stream, "}\n"); + return OPJ_TRUE; +} + +opj_bool j2k_set_decoded_resolution_factor(opj_j2k_v2_t *p_j2k, OPJ_UINT32 res_factor, opj_event_mgr_t * p_manager) +{ + OPJ_UINT32 it_comp; + + p_j2k->m_cp.m_specific_param.m_dec.m_reduce = res_factor; + + if (p_j2k->m_private_image) { + if (p_j2k->m_private_image->comps) { + if (p_j2k->m_specific_param.m_decoder.m_default_tcp) { + if (p_j2k->m_specific_param.m_decoder.m_default_tcp->tccps) { + for (it_comp = 0 ; it_comp < p_j2k->m_private_image->numcomps; it_comp++) { + OPJ_UINT32 max_res = p_j2k->m_specific_param.m_decoder.m_default_tcp->tccps[it_comp].numresolutions; + if ( res_factor >= max_res){ + opj_event_msg_v2(p_manager, EVT_ERROR, "Resolution factor is greater than the maximum resolution in the component.\n"); + return OPJ_FALSE; + } + p_j2k->m_private_image->comps[it_comp].factor = res_factor; + } + return OPJ_TRUE; + } + } + } + } + return OPJ_FALSE; } + /** - * Dump an image header structure. - * - *@param img_header the image header to dump. - *@param dev_dump_flag flag to describe if we are in the case of this function is use outside j2k_dump function - *@param out_stream output stream where dump the elements. + * Encodes all the tiles in a row. */ -void j2k_dump_image_header(opj_image_t* img_header, opj_bool dev_dump_flag, FILE* out_stream) +opj_bool j2k_encode_v2( opj_j2k_v2_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ) { - char tab[2]; + OPJ_UINT32 i; + OPJ_UINT32 l_nb_tiles; + OPJ_UINT32 l_max_tile_size, l_current_tile_size; + OPJ_BYTE * l_current_data; - if (dev_dump_flag){ - fprintf(stdout, "[DEV] Dump a image_header struct {\n"); - tab[0] = '\0'; - } - else { - fprintf(out_stream, "Image info {\n"); - tab[0] = '\t';tab[1] = '\0'; + /* preconditions */ + assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); + + l_current_data = (OPJ_BYTE*)opj_malloc(1000); + if (! l_current_data) { + return OPJ_FALSE; } + l_max_tile_size = 1000; - fprintf(out_stream, "%s x0=%d, y0=%d\n", tab, img_header->x0, img_header->y0); - fprintf(out_stream, "%s x1=%d, y1=%d\n", tab, img_header->x1, img_header->y1); - fprintf(out_stream, "%s numcomps=%d\n", tab, img_header->numcomps); + l_nb_tiles = p_j2k->m_cp.th * p_j2k->m_cp.tw; + for (i=0;icomps){ - int compno; - for (compno = 0; compno < img_header->numcomps; compno++) { - fprintf(out_stream, "%s\t component %d {\n", tab, compno); - j2k_dump_image_comp_header(&(img_header->comps[compno]), dev_dump_flag, out_stream); - fprintf(out_stream,"%s}\n",tab); + l_current_tile_size = tcd_get_encoded_tile_size(p_j2k->m_tcd); + if (l_current_tile_size > l_max_tile_size) { + l_current_data = (OPJ_BYTE*)opj_realloc(l_current_data,l_current_tile_size); + if (! l_current_data) { + return OPJ_FALSE; + } + l_max_tile_size = l_current_tile_size; + } + + j2k_get_tile_data(p_j2k->m_tcd,l_current_data); + + if (! j2k_post_write_tile (p_j2k,l_current_data,l_current_tile_size,p_stream,p_manager)) { + return OPJ_FALSE; } } - fprintf(out_stream, "}\n"); + opj_free(l_current_data); + return OPJ_TRUE; } /** - * Dump a component image header structure. - * - *@param comp_header the component image header to dump. - *@param dev_dump_flag flag to describe if we are in the case of this function is use outside j2k_dump function - *@param out_stream output stream where dump the elements. + * Ends the compression procedures and possibility add data to be read after the + * codestream. */ -void j2k_dump_image_comp_header(opj_image_comp_t* comp_header, opj_bool dev_dump_flag, FILE* out_stream) +opj_bool j2k_end_compress( opj_j2k_v2_t *p_j2k, + opj_stream_private_t *p_stream, + struct opj_event_mgr * p_manager) { - char tab[3]; + /* customization of the encoding */ + j2k_setup_end_compress(p_j2k); - if (dev_dump_flag){ - fprintf(stdout, "[DEV] Dump a image_comp_header struct {\n"); - tab[0] = '\0'; - } else { - tab[0] = '\t';tab[1] = '\t';tab[2] = '\0'; + if (! j2k_exec (p_j2k, p_j2k->m_procedure_list, p_stream, p_manager)) + { + return OPJ_FALSE; } - fprintf(out_stream, "%s dx=%d, dy=%d\n", tab, comp_header->dx, comp_header->dy); - fprintf(out_stream, "%s prec=%d\n", tab, comp_header->prec); - fprintf(out_stream, "%s sgnd=%d\n", tab, comp_header->sgnd); - - if (dev_dump_flag) - fprintf(out_stream, "}\n"); + return OPJ_TRUE; } /** - * Get the codestream info from a JPEG2000 codec. + * Starts a compression scheme, i.e. validates the codec parameters, writes the header. * - *@param p_j2k the component image header to dump. + * @param p_j2k the jpeg2000 codec. + * @param p_stream the stream object. + * @param p_manager the user event manager. * - *@return the codestream information extract from the jpg2000 codec + * @return true if the codec is valid. */ -opj_codestream_info_v2_t* j2k_get_cstr_info(opj_j2k_v2_t* p_j2k) +opj_bool j2k_start_compress(opj_j2k_v2_t *p_j2k, + opj_stream_private_t *p_stream, + opj_image_t * p_image, + opj_event_mgr_t * p_manager) { - OPJ_UINT16 compno; - OPJ_UINT16 numcomps = p_j2k->m_private_image->numcomps; - opj_tcp_v2_t *l_default_tile; - opj_codestream_info_v2_t* cstr_info = (opj_codestream_info_v2_t*) opj_calloc(1,sizeof(opj_codestream_info_v2_t)); + /* preconditions */ + assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); - cstr_info->nbcomps = p_j2k->m_private_image->numcomps; + p_j2k->m_private_image = opj_image_create0(); + opj_copy_image_header(p_image, p_j2k->m_private_image); - cstr_info->tx0 = p_j2k->m_cp.tx0; - cstr_info->ty0 = p_j2k->m_cp.ty0; - cstr_info->tdx = p_j2k->m_cp.tdx; - cstr_info->tdy = p_j2k->m_cp.tdy; - cstr_info->tw = p_j2k->m_cp.tw; - cstr_info->th = p_j2k->m_cp.th; + // TODO_MSD: Find a better way + if (p_image->comps) { + OPJ_UINT32 it_comp; + for (it_comp = 0 ; it_comp < p_image->numcomps; it_comp++) { + if (p_image->comps[it_comp].data) { + p_j2k->m_private_image->comps[it_comp].data =p_image->comps[it_comp].data; + p_image->comps[it_comp].data = NULL; - cstr_info->tile_info = NULL; /* Not fill from the main header*/ + } + } + } - l_default_tile = p_j2k->m_specific_param.m_decoder.m_default_tcp; + /* customization of the validation */ + j2k_setup_encoding_validation (p_j2k); - cstr_info->m_default_tile_info.csty = l_default_tile->csty; - cstr_info->m_default_tile_info.prg = l_default_tile->prg; - cstr_info->m_default_tile_info.numlayers = l_default_tile->numlayers; - cstr_info->m_default_tile_info.mct = l_default_tile->mct; + /* validation of the parameters codec */ + if (! j2k_exec(p_j2k,p_j2k->m_validation_list,p_stream,p_manager)) { + return OPJ_FALSE; + } - cstr_info->m_default_tile_info.tccp_info = (opj_tccp_info_t*) opj_calloc(cstr_info->nbcomps, sizeof(opj_tccp_info_t)); + /* customization of the encoding */ + j2k_setup_header_writting(p_j2k); - for (compno = 0; compno < numcomps; compno++) { - opj_tccp_t *l_tccp = &(l_default_tile->tccps[compno]); - opj_tccp_info_t *l_tccp_info = &(cstr_info->m_default_tile_info.tccp_info[compno]); - OPJ_INT32 bandno, numbands; + /* write header */ + if (! j2k_exec (p_j2k,p_j2k->m_procedure_list,p_stream,p_manager)) { + return OPJ_FALSE; + } - /* coding style*/ - l_tccp_info->csty = l_tccp->csty; - l_tccp_info->numresolutions = l_tccp->numresolutions; - l_tccp_info->cblkw = l_tccp->cblkw; - l_tccp_info->cblkh = l_tccp->cblkh; - l_tccp_info->cblksty = l_tccp->cblksty; - l_tccp_info->qmfbid = l_tccp->qmfbid; - if (l_tccp->numresolutions < J2K_MAXRLVLS) - { - memcpy(l_tccp_info->prch, l_tccp->prch, l_tccp->numresolutions); - memcpy(l_tccp_info->prcw, l_tccp->prcw, l_tccp->numresolutions); - } + return OPJ_TRUE; +} - /* quantization style*/ - l_tccp_info->qntsty = l_tccp->qntsty; - l_tccp_info->numgbits = l_tccp->numgbits; +/* + * + */ +opj_bool j2k_pre_write_tile ( opj_j2k_v2_t * p_j2k, + OPJ_UINT32 p_tile_index, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ) +{ + (void)p_stream; + if (p_tile_index != p_j2k->m_current_tile_number) { + opj_event_msg_v2(p_manager, EVT_ERROR, "The given tile index does not match." ); + return OPJ_FALSE; + } - numbands = (l_tccp->qntsty == J2K_CCP_QNTSTY_SIQNT) ? 1 : l_tccp->numresolutions * 3 - 2; - if (numbands < J2K_MAXBANDS) { - for (bandno = 0; bandno < numbands; bandno++) { - l_tccp_info->stepsizes_mant[bandno] = l_tccp->stepsizes[bandno].mant; - l_tccp_info->stepsizes_expn[bandno] = l_tccp->stepsizes[bandno].expn; - } - } + opj_event_msg_v2(p_manager, EVT_INFO, "tile number %d / %d\n", p_j2k->m_current_tile_number + 1, p_j2k->m_cp.tw * p_j2k->m_cp.th); - /* RGN value*/ - l_tccp_info->roishift = l_tccp->roishift; + p_j2k->m_specific_param.m_encoder.m_current_tile_part_number = 0; + p_j2k->m_tcd->cur_totnum_tp = p_j2k->m_cp.tcps[p_tile_index].m_nb_tile_parts; + p_j2k->m_specific_param.m_encoder.m_current_poc_tile_part_number = 0; + + /* initialisation before tile encoding */ + if (! tcd_init_encode_tile(p_j2k->m_tcd, p_j2k->m_current_tile_number)) { + return OPJ_FALSE; } + return OPJ_TRUE; +} - return cstr_info; +/* + * + */ +void j2k_get_tile_data (opj_tcd_v2_t * p_tcd, OPJ_BYTE * p_data) +{ + OPJ_UINT32 i,j,k = 0; + OPJ_UINT32 l_width,l_height,l_stride, l_offset_x,l_offset_y, l_image_width; + opj_image_comp_t * l_img_comp = 00; + opj_tcd_tilecomp_v2_t * l_tilec = 00; + opj_image_t * l_image = 00; + OPJ_UINT32 l_size_comp, l_remaining; + OPJ_INT32 * l_src_ptr; + l_tilec = p_tcd->tcd_image->tiles->comps; + l_image = p_tcd->image; + l_img_comp = l_image->comps; + + for (i=0;iimage->numcomps;++i) { + l_size_comp = l_img_comp->prec >> 3; /* (/8) */ + l_remaining = l_img_comp->prec & 7; /* (%8) */ + if (l_remaining) { + ++l_size_comp; + } + + if (l_size_comp == 3) { + l_size_comp = 4; + } + + l_width = (l_tilec->x1 - l_tilec->x0); + l_height = (l_tilec->y1 - l_tilec->y0); + l_offset_x = int_ceildiv(l_image->x0, l_img_comp->dx); + l_offset_y = int_ceildiv(l_image->y0, l_img_comp->dy); + l_image_width = int_ceildiv(l_image->x1 - l_image->x0, l_img_comp->dx); + l_stride = l_image_width - l_width; + l_src_ptr = l_img_comp->data + (l_tilec->x0 - l_offset_x) + (l_tilec->y0 - l_offset_y) * l_image_width; + + switch (l_size_comp) { + case 1: + { + OPJ_CHAR * l_dest_ptr = (OPJ_CHAR*) p_data; + if (l_img_comp->sgnd) { + for (j=0;jsgnd) { + for (j=0;jmain_head_start = p_j2k->cstr_index->main_head_start; - l_cstr_index->main_head_end = p_j2k->cstr_index->main_head_end; - l_cstr_index->codestream_size = p_j2k->cstr_index->codestream_size; + /* preconditions */ + assert(p_j2k->m_specific_param.m_encoder.m_encoded_tile_data); - l_cstr_index->marknum = p_j2k->cstr_index->marknum; - l_cstr_index->marker = (opj_marker_info_t*)opj_malloc(l_cstr_index->marknum*sizeof(opj_marker_info_t)); - if (!l_cstr_index->marker){ - opj_free( l_cstr_index); - return NULL; + l_tcd = p_j2k->m_tcd; + l_cp = &(p_j2k->m_cp); + l_tcp = l_cp->tcps + p_j2k->m_current_tile_number; + + l_tile_size = p_j2k->m_specific_param.m_encoder.m_encoded_tile_size; + l_available_data = l_tile_size; + l_current_data = p_j2k->m_specific_param.m_encoder.m_encoded_tile_data; + + if (! tcd_copy_tile_data(l_tcd,p_data,p_data_size)) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Size mismatch between tile data and sent data." ); + return OPJ_FALSE; } - if (p_j2k->cstr_index->marker) - memcpy(l_cstr_index->marker, p_j2k->cstr_index->marker, l_cstr_index->marknum * sizeof(opj_marker_info_t) ); - else{ - opj_free(l_cstr_index->marker); - l_cstr_index->marker = NULL; + l_nb_bytes_written = 0; + if (! j2k_write_first_tile_part(p_j2k,l_current_data,&l_nb_bytes_written,l_available_data,p_stream,p_manager)) { + return OPJ_FALSE; } + l_current_data += l_nb_bytes_written; + l_available_data -= l_nb_bytes_written; - l_cstr_index->nb_of_tiles = p_j2k->cstr_index->nb_of_tiles; - l_cstr_index->tile_index = (opj_tile_index_t*)opj_calloc(l_cstr_index->nb_of_tiles, sizeof(opj_tile_index_t) ); - if (!l_cstr_index->tile_index){ - opj_free( l_cstr_index->marker); - opj_free( l_cstr_index); - return NULL; + l_nb_bytes_written = 0; + if (! j2k_write_all_tile_parts(p_j2k,l_current_data,&l_nb_bytes_written,l_available_data,p_stream,p_manager)) { + return OPJ_FALSE; } - if (!p_j2k->cstr_index->tile_index){ - opj_free(l_cstr_index->tile_index); - l_cstr_index->tile_index = NULL; + l_available_data -= l_nb_bytes_written; + l_nb_bytes_written = l_tile_size - l_available_data; + + if ( opj_stream_write_data( p_stream, + p_j2k->m_specific_param.m_encoder.m_encoded_tile_data, + l_nb_bytes_written,p_manager) != l_nb_bytes_written) { + return OPJ_FALSE; } - else { - OPJ_UINT32 it_tile = 0; - for (it_tile = 0; it_tile < l_cstr_index->nb_of_tiles; it_tile++ ){ - /* Tile Marker*/ - l_cstr_index->tile_index[it_tile].marknum = p_j2k->cstr_index->tile_index[it_tile].marknum; + ++p_j2k->m_current_tile_number; - l_cstr_index->tile_index[it_tile].marker = - (opj_marker_info_t*)opj_malloc(l_cstr_index->tile_index[it_tile].marknum*sizeof(opj_marker_info_t)); + return OPJ_TRUE; +} - if (!l_cstr_index->tile_index[it_tile].marker) { - OPJ_UINT32 it_tile_free; - for (it_tile_free=0; it_tile_free < it_tile; it_tile_free++){ - opj_free(l_cstr_index->tile_index[it_tile_free].marker); - } +/** + * Sets up the validation ,i.e. adds the procedures to lauch to make sure the codec parameters + * are valid. Developers wanting to extend the library can add their own validation procedures. + */ +void j2k_setup_end_compress (opj_j2k_v2_t *p_j2k) +{ + /* preconditions */ + assert(p_j2k != 00); - opj_free( l_cstr_index->tile_index); - opj_free( l_cstr_index->marker); - opj_free( l_cstr_index); - return NULL; - } + /* DEVELOPER CORNER, insert your custom procedures */ + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)j2k_write_eoc_v2 ); - if (p_j2k->cstr_index->tile_index[it_tile].marker) - memcpy( l_cstr_index->tile_index[it_tile].marker, - p_j2k->cstr_index->tile_index[it_tile].marker, - l_cstr_index->tile_index[it_tile].marknum * sizeof(opj_marker_info_t) ); - else{ - opj_free(l_cstr_index->tile_index[it_tile].marker); - l_cstr_index->tile_index[it_tile].marker = NULL; - } + if (p_j2k->m_cp.m_specific_param.m_enc.m_cinema) { + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)j2k_write_updated_tlm); + } - /* Tile part index*/ - l_cstr_index->tile_index[it_tile].nb_tps = p_j2k->cstr_index->tile_index[it_tile].nb_tps; + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)j2k_write_epc ); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)j2k_end_encoding ); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)j2k_destroy_header_memory); +} - l_cstr_index->tile_index[it_tile].tp_index = - (opj_tp_index_t*)opj_malloc(l_cstr_index->tile_index[it_tile].nb_tps*sizeof(opj_tp_index_t)); +/** + * Sets up the validation ,i.e. adds the procedures to lauch to make sure the codec parameters + * are valid. Developers wanting to extend the library can add their own validation procedures. + */ +void j2k_setup_encoding_validation (opj_j2k_v2_t *p_j2k) +{ + /* preconditions */ + assert(p_j2k != 00); - if(!l_cstr_index->tile_index[it_tile].tp_index){ - OPJ_UINT32 it_tile_free; + opj_procedure_list_add_procedure(p_j2k->m_validation_list, (opj_procedure)j2k_build_encoder); + opj_procedure_list_add_procedure(p_j2k->m_validation_list, (opj_procedure)j2k_encoding_validation); - for (it_tile_free=0; it_tile_free < it_tile; it_tile_free++){ - opj_free(l_cstr_index->tile_index[it_tile_free].marker); - opj_free(l_cstr_index->tile_index[it_tile_free].tp_index); - } + /* DEVELOPER CORNER, add your custom validation procedure */ + opj_procedure_list_add_procedure(p_j2k->m_validation_list, (opj_procedure)j2k_mct_validation); +} - opj_free( l_cstr_index->tile_index); - opj_free( l_cstr_index->marker); - opj_free( l_cstr_index); - return NULL; - } - if (p_j2k->cstr_index->tile_index[it_tile].tp_index){ - memcpy( l_cstr_index->tile_index[it_tile].tp_index, - p_j2k->cstr_index->tile_index[it_tile].tp_index, - l_cstr_index->tile_index[it_tile].nb_tps * sizeof(opj_tp_index_t) ); - } - else{ - opj_free(l_cstr_index->tile_index[it_tile].tp_index); - l_cstr_index->tile_index[it_tile].tp_index = NULL; - } +/** + * Sets up the procedures to do on writing header. + * Developers wanting to extend the library can add their own writing procedures. + */ +void j2k_setup_header_writting (opj_j2k_v2_t *p_j2k) +{ + /* preconditions */ + assert(p_j2k != 00); + + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)j2k_init_info ); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)j2k_write_soc_v2 ); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)j2k_write_siz_v2 ); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)j2k_write_cod_v2 ); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)j2k_write_qcd_v2 ); - /* Packet index (NOT USED)*/ - l_cstr_index->tile_index[it_tile].nb_packet = 0; - l_cstr_index->tile_index[it_tile].packet_index = NULL; + if (p_j2k->m_cp.m_specific_param.m_enc.m_cinema) { + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)j2k_write_image_components ); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)j2k_write_tlm_v2 ); + + if (p_j2k->m_cp.m_specific_param.m_enc.m_cinema == CINEMA4K_24) { + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)j2k_write_poc_v2 ); } } - return l_cstr_index; -} + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)j2k_write_regions); -opj_bool j2k_allocate_tile_element_cstr_index(opj_j2k_v2_t *p_j2k) -{ - OPJ_UINT32 it_tile=0; + if (p_j2k->m_cp.comment != 00) { + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)j2k_write_com_v2); + } - p_j2k->cstr_index->nb_of_tiles = p_j2k->m_cp.tw * p_j2k->m_cp.tw; - p_j2k->cstr_index->tile_index = (opj_tile_index_t*)opj_calloc(p_j2k->cstr_index->nb_of_tiles, sizeof(opj_tile_index_t)); - if (!p_j2k->cstr_index->tile_index) - return OPJ_FALSE; + /* DEVELOPER CORNER, insert your custom procedures */ + if (p_j2k->m_cp.rsiz & MCT) { + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)j2k_write_mct_data_group ); + } + /* End of Developer Corner */ - for (it_tile=0; it_tile < p_j2k->cstr_index->nb_of_tiles; it_tile++){ - p_j2k->cstr_index->tile_index[it_tile].maxmarknum = 100; - p_j2k->cstr_index->tile_index[it_tile].marknum = 0; - p_j2k->cstr_index->tile_index[it_tile].marker = (opj_marker_info_t*) - opj_calloc(p_j2k->cstr_index->tile_index[it_tile].maxmarknum, sizeof(opj_marker_info_t)); - if (!p_j2k->cstr_index->tile_index[it_tile].marker) - return OPJ_FALSE; + if (p_j2k->cstr_index) { + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)j2k_get_end_header ); } - return OPJ_TRUE; + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)j2k_create_tcd); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)j2k_update_rates); } -/** - * Reads the tiles. - */ -opj_bool j2k_decode_tiles ( opj_j2k_v2_t *p_j2k, - opj_stream_private_t *p_stream, - opj_event_mgr_t * p_manager) + +opj_bool j2k_write_first_tile_part (opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 p_total_data_size, + opj_stream_private_t *p_stream, + struct opj_event_mgr * 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 compno; + OPJ_UINT32 l_nb_bytes_written = 0; + OPJ_UINT32 l_current_nb_bytes_written; + OPJ_BYTE * l_begin_data = 00; - l_current_data = (OPJ_BYTE*)opj_malloc(1000); - if (! l_current_data) { - return OPJ_FALSE; - } - l_max_data_size = 1000; + opj_tcp_v2_t *l_tcp = 00; + opj_tcd_v2_t * l_tcd = 00; + opj_cp_v2_t * l_cp = 00; - /*Allocate and initialize some elements of codestrem index*/ - if (!j2k_allocate_tile_element_cstr_index(p_j2k)) - return OPJ_FALSE; + l_tcd = p_j2k->m_tcd; + l_cp = &(p_j2k->m_cp); + l_tcp = l_cp->tcps + p_j2k->m_current_tile_number; - while (OPJ_TRUE) { - if (! 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; - } + l_tcd->cur_pino = 0; - if (! l_go_on) { - break; - } + /*Get number of tile parts*/ + p_j2k->m_specific_param.m_encoder.m_current_poc_tile_part_number = 0; - if (l_data_size > l_max_data_size) { - l_current_data = (OPJ_BYTE*)opj_realloc(l_current_data,l_data_size); - if (! l_current_data) { - return OPJ_FALSE; - } + /* INDEX >> */ + /* << INDEX */ - l_max_data_size = l_data_size; - } + l_current_nb_bytes_written = 0; + l_begin_data = p_data; + if (! j2k_write_sot_v2(p_j2k,p_data,&l_current_nb_bytes_written,p_stream,p_manager)) + { + return OPJ_FALSE; + } - if (! j2k_decode_tile(p_j2k,l_current_tile_no,l_current_data,l_data_size,p_stream,p_manager)) { - opj_free(l_current_data); - 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; + + if (l_cp->m_specific_param.m_enc.m_cinema == 0) { + for (compno = 1; compno < p_j2k->m_private_image->numcomps; compno++) { + l_current_nb_bytes_written = 0; + j2k_write_coc_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; + + l_current_nb_bytes_written = 0; + 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; } - opj_event_msg_v2(p_manager, EVT_INFO, "Tile %d/%d has been decode.\n", l_current_tile_no +1, p_j2k->m_cp.th * p_j2k->m_cp.tw); - if (! j2k_update_image_data(p_j2k->m_tcd,l_current_data, p_j2k->m_output_image)) { - opj_free(l_current_data); - return OPJ_FALSE; + if (l_cp->tcps[p_j2k->m_current_tile_number].numpocs) { + l_current_nb_bytes_written = 0; + 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; } - opj_event_msg_v2(p_manager, EVT_INFO, "Image data has been updated with tile %d.\n\n", l_current_tile_no + 1); + } + l_current_nb_bytes_written = 0; + if (! j2k_write_sod_v2(p_j2k,l_tcd,p_data,&l_current_nb_bytes_written,p_total_data_size,p_stream,p_manager)) { + return OPJ_FALSE; } - opj_free(l_current_data); + l_nb_bytes_written += l_current_nb_bytes_written; + * p_data_written = l_nb_bytes_written; + + /* Writing Psot in SOT marker */ + opj_write_bytes(l_begin_data + 6,l_nb_bytes_written,4); /* PSOT */ + + if (l_cp->m_specific_param.m_enc.m_cinema){ + j2k_update_tlm(p_j2k,l_nb_bytes_written); + } return OPJ_TRUE; } -/** - * Sets up the procedures to do on decoding data. Developpers wanting to extend the library can add their own reading procedures. - */ -void j2k_setup_decoding (opj_j2k_v2_t *p_j2k) +opj_bool j2k_write_all_tile_parts( opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 p_total_data_size, + opj_stream_private_t *p_stream, + struct opj_event_mgr * p_manager + ) { - // preconditions - assert(p_j2k != 00); + OPJ_UINT32 tilepartno=0; + OPJ_UINT32 l_nb_bytes_written = 0; + OPJ_UINT32 l_current_nb_bytes_written; + OPJ_UINT32 l_part_tile_size; + OPJ_UINT32 tot_num_tp; + OPJ_UINT32 pino; + + OPJ_BYTE * l_begin_data; + opj_tcp_v2_t *l_tcp = 00; + opj_tcd_v2_t * l_tcd = 00; + opj_cp_v2_t * l_cp = 00; - opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_decode_tiles); - /* DEVELOPER CORNER, add your custom procedures */ -} + l_tcd = p_j2k->m_tcd; + l_cp = &(p_j2k->m_cp); + l_tcp = l_cp->tcps + p_j2k->m_current_tile_number; -/* - * Read and decode one tile. - */ -opj_bool j2k_decode_one_tile ( opj_j2k_v2_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_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; + /*Get number of tile parts*/ + tot_num_tp = j2k_get_num_tp_v2(l_cp,0,p_j2k->m_current_tile_number); - l_current_data = (OPJ_BYTE*)opj_malloc(1000); - if (! l_current_data) { - return OPJ_FALSE; - } - l_max_data_size = 1000; + for (tilepartno = 1; tilepartno < tot_num_tp ; ++tilepartno) { + p_j2k->m_specific_param.m_encoder.m_current_poc_tile_part_number = tilepartno; + l_current_nb_bytes_written = 0; + l_part_tile_size = 0; + l_begin_data = p_data; - /*Allocate and initialize some elements of codestrem index if not already done*/ - if( !p_j2k->cstr_index->tile_index) - { - if (!j2k_allocate_tile_element_cstr_index(p_j2k)) + if (! j2k_write_sot_v2(p_j2k,p_data,&l_current_nb_bytes_written,p_stream,p_manager)) { return OPJ_FALSE; - } - /* Move into the codestream to the first SOT used to decode the desired tile */ - l_tile_no_to_dec = p_j2k->m_specific_param.m_decoder.m_tile_ind_to_dec; - if (p_j2k->cstr_index->tile_index) - if(p_j2k->cstr_index->tile_index->tp_index) - { - if ( ! p_j2k->cstr_index->tile_index[l_tile_no_to_dec].nb_tps) { - /* the index for this tile has not been built, - * so move to the last SOT read */ - 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_v2(p_manager, EVT_ERROR, "Problem with seek function\n"); - return OPJ_FALSE; - } - } - else{ - if (opj_stream_read_seek(p_stream, p_j2k->cstr_index->tile_index[l_tile_no_to_dec].tp_index[0].start_pos+2, p_manager)) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Problem with seek function\n"); - return OPJ_FALSE; - } - } - /* Special case if we have previously read the EOC marker (if the previous tile getted is the last ) */ - if(p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_EOC) - p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_TPHSOT; } - while (OPJ_TRUE) { - if (! 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); + 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; + l_part_tile_size += l_nb_bytes_written; + + l_current_nb_bytes_written = 0; + if (! j2k_write_sod_v2(p_j2k,l_tcd,p_data,&l_current_nb_bytes_written,p_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; + l_part_tile_size += l_nb_bytes_written; - if (! l_go_on) { - break; + /* Writing Psot in SOT marker */ + opj_write_bytes(l_begin_data + 6,l_part_tile_size,4); /* PSOT */ + + if (l_cp->m_specific_param.m_enc.m_cinema) { + j2k_update_tlm(p_j2k,l_part_tile_size); } - if (l_data_size > l_max_data_size) { - l_current_data = (OPJ_BYTE*)opj_realloc(l_current_data,l_data_size); - if (! l_current_data) { + ++p_j2k->m_specific_param.m_encoder.m_current_tile_part_number; + } + + for (pino = 1; pino <= l_tcp->numpocs; ++pino) { + l_tcd->cur_pino = pino; + + /*Get number of tile parts*/ + tot_num_tp = j2k_get_num_tp_v2(l_cp,pino,p_j2k->m_current_tile_number); + for (tilepartno = 0; tilepartno < tot_num_tp ; ++tilepartno) { + p_j2k->m_specific_param.m_encoder.m_current_poc_tile_part_number = tilepartno; + l_current_nb_bytes_written = 0; + l_part_tile_size = 0; + l_begin_data = p_data; + + if (! j2k_write_sot_v2(p_j2k,p_data,&l_current_nb_bytes_written,p_stream,p_manager)) { return OPJ_FALSE; } - l_max_data_size = l_data_size; - } + 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; + l_part_tile_size += l_current_nb_bytes_written; + l_current_nb_bytes_written = 0; + if (! j2k_write_sod_v2(p_j2k,l_tcd,p_data,&l_current_nb_bytes_written,p_total_data_size,p_stream,p_manager)) { + return OPJ_FALSE; + } - if (! j2k_decode_tile(p_j2k,l_current_tile_no,l_current_data,l_data_size,p_stream,p_manager)) { - opj_free(l_current_data); - return OPJ_FALSE; - } - opj_event_msg_v2(p_manager, EVT_INFO, "Tile %d/%d has been decode.\n", l_current_tile_no, (p_j2k->m_cp.th * p_j2k->m_cp.tw) - 1); + 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; + l_part_tile_size += l_current_nb_bytes_written; - if (! j2k_update_image_data(p_j2k->m_tcd,l_current_data, p_j2k->m_output_image)) { - opj_free(l_current_data); - return OPJ_FALSE; - } - opj_event_msg_v2(p_manager, EVT_INFO, "Image data has been updated with tile %d.\n\n", l_current_tile_no); + /* Writing Psot in SOT marker */ + opj_write_bytes(l_begin_data + 6,l_part_tile_size,4); /* PSOT */ - if(l_current_tile_no == l_tile_no_to_dec) - { - /* move into the codestream to the the first SOT (FIXME or not move?)*/ - if (opj_stream_read_seek(p_stream, p_j2k->cstr_index->main_head_end + 2, p_manager) ) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Problem with seek function\n"); - return OPJ_FALSE; + if (l_cp->m_specific_param.m_enc.m_cinema) { + j2k_update_tlm(p_j2k,l_part_tile_size); } - break; - } - else { - opj_event_msg_v2(p_manager, EVT_WARNING, "Tile read, decode and updated is not the desired (%d vs %d).\n", l_current_tile_no, l_tile_no_to_dec); - } + ++p_j2k->m_specific_param.m_encoder.m_current_tile_part_number; + } } - opj_free(l_current_data); + *p_data_written = l_nb_bytes_written; 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. - */ -void j2k_setup_decoding_tile (opj_j2k_v2_t *p_j2k) + * Writes the updated tlm. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +opj_bool j2k_write_updated_tlm( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) { - // preconditions + OPJ_UINT32 l_tlm_size; + OPJ_SIZE_T l_tlm_position, l_current_position; + + /* preconditions */ assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); - opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_decode_one_tile); - /* DEVELOPER CORNER, add your custom procedures */ + l_tlm_size = 5 * 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); + + if (! opj_stream_seek(p_stream,l_tlm_position,p_manager)) { + return OPJ_FALSE; + } + if (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer,l_tlm_size,p_manager) != l_tlm_size) { + return OPJ_FALSE; + } + + if (! opj_stream_seek(p_stream,l_current_position,p_manager)) { + return OPJ_FALSE; + } + + return OPJ_TRUE; } /** - * Decodes the tiles of the stream. - */ -opj_bool j2k_decode_v2( opj_j2k_v2_t * p_j2k, - opj_stream_private_t * p_stream, - opj_image_t * p_image, - opj_event_mgr_t * p_manager) + * Ends the encoding, i.e. frees memory. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +opj_bool j2k_end_encoding( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) { - OPJ_UINT32 compno; + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); - if (!p_image) - return OPJ_FALSE; + tcd_destroy_v2(p_j2k->m_tcd); + p_j2k->m_tcd = 00; - p_j2k->m_output_image = opj_image_create0(); - if (! (p_j2k->m_output_image)) { - return OPJ_FALSE; + if (p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer) { + opj_free(p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer); + p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer = 0; + p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current = 0; } - opj_copy_image_header(p_image, p_j2k->m_output_image); - - /* customization of the decoding */ - j2k_setup_decoding(p_j2k); - /* Decode the codestream */ - if (! j2k_exec (p_j2k,p_j2k->m_procedure_list,p_stream,p_manager)) { - opj_image_destroy(p_j2k->m_private_image); - p_j2k->m_private_image = NULL; - return OPJ_FALSE; + if (p_j2k->m_specific_param.m_encoder.m_encoded_tile_data) { + opj_free(p_j2k->m_specific_param.m_encoder.m_encoded_tile_data); + p_j2k->m_specific_param.m_encoder.m_encoded_tile_data = 0; } - /* 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; - p_j2k->m_output_image->comps[compno].data = NULL; + p_j2k->m_specific_param.m_encoder.m_encoded_tile_size = 0; + + return OPJ_TRUE; +} + +/** + * Destroys the memory associated with the decoding of headers. + */ +opj_bool j2k_destroy_header_memory (opj_j2k_v2_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ) +{ + /* preconditions */ + assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); + + if (p_j2k->m_specific_param.m_encoder.m_header_tile_data) { + opj_free(p_j2k->m_specific_param.m_encoder.m_header_tile_data); + p_j2k->m_specific_param.m_encoder.m_header_tile_data = 0; } + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = 0; + return OPJ_TRUE; } /** - * Get the decoded tile. - * - * @param p_j2k the jpeg2000 codestream codec. - * @param p_stream input_stream - * @param p_image output image. . - * @param p_manager the user event manager - * @param tile_index index of the tile we want decode + * Inits the Info * - * @return true if succeed. - */ -opj_bool j2k_get_tile( opj_j2k_v2_t *p_j2k, - opj_stream_private_t *p_stream, - opj_image_t* p_image, - struct opj_event_mgr * p_manager, - OPJ_UINT32 tile_index ) + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +opj_bool j2k_init_info( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) { - OPJ_UINT32 compno; - OPJ_UINT32 l_tile_x, l_tile_y; - opj_image_comp_t* l_img_comp; + opj_codestream_info_t * l_cstr_info = 00; - if (!p_image) { - opj_event_msg_v2(p_manager, EVT_ERROR, "We need a image previously created.\n"); - return OPJ_FALSE; - } + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + (void)l_cstr_info; - if ( (tile_index < 0) && (tile_index >= p_j2k->m_cp.tw * p_j2k->m_cp.th) ){ - opj_event_msg_v2(p_manager, EVT_ERROR, "Tile index provided by the user is incorrect %d (max = %d) \n", tile_index, (p_j2k->m_cp.tw * p_j2k->m_cp.th) - 1); - return OPJ_FALSE; - } + /* TODO mergeV2: check this part which use cstr_info */ + /*l_cstr_info = p_j2k->cstr_info; - /* Compute the dimension of the desired tile*/ - l_tile_x = tile_index % p_j2k->m_cp.tw; - l_tile_y = tile_index / p_j2k->m_cp.tw; + if (l_cstr_info) { + OPJ_UINT32 compno; + l_cstr_info->tile = (opj_tile_info_t *) opj_malloc(p_j2k->m_cp.tw * p_j2k->m_cp.th * sizeof(opj_tile_info_t)); - p_image->x0 = l_tile_x * p_j2k->m_cp.tdx + p_j2k->m_cp.tx0; - if (p_image->x0 < p_j2k->m_private_image->x0) - p_image->x0 = p_j2k->m_private_image->x0; - p_image->x1 = (l_tile_x + 1) * p_j2k->m_cp.tdx + p_j2k->m_cp.tx0; - if (p_image->x1 > p_j2k->m_private_image->x1) - p_image->x1 = p_j2k->m_private_image->x1; + l_cstr_info->image_w = p_j2k->m_image->x1 - p_j2k->m_image->x0; + l_cstr_info->image_h = p_j2k->m_image->y1 - p_j2k->m_image->y0; - p_image->y0 = l_tile_y * p_j2k->m_cp.tdy + p_j2k->m_cp.ty0; - if (p_image->y0 < p_j2k->m_private_image->y0) - p_image->y0 = p_j2k->m_private_image->y0; - p_image->y1 = (l_tile_y + 1) * p_j2k->m_cp.tdy + p_j2k->m_cp.ty0; - if (p_image->y1 > p_j2k->m_private_image->y1) - p_image->y1 = p_j2k->m_private_image->y1; + l_cstr_info->prog = (&p_j2k->m_cp.tcps[0])->prg; - l_img_comp = p_image->comps; - for (compno=0; compno < p_image->numcomps; ++compno) - { - OPJ_INT32 l_comp_x1, l_comp_y1; + l_cstr_info->tw = p_j2k->m_cp.tw; + l_cstr_info->th = p_j2k->m_cp.th; - l_img_comp->factor = p_j2k->m_private_image->comps[compno].factor; + l_cstr_info->tile_x = p_j2k->m_cp.tdx;*/ /* new version parser */ + /*l_cstr_info->tile_y = p_j2k->m_cp.tdy;*/ /* new version parser */ + /*l_cstr_info->tile_Ox = p_j2k->m_cp.tx0;*/ /* new version parser */ + /*l_cstr_info->tile_Oy = p_j2k->m_cp.ty0;*/ /* new version parser */ - l_img_comp->x0 = int_ceildiv(p_image->x0, l_img_comp->dx); - l_img_comp->y0 = int_ceildiv(p_image->y0, l_img_comp->dy); - l_comp_x1 = int_ceildiv(p_image->x1, l_img_comp->dx); - l_comp_y1 = int_ceildiv(p_image->y1, l_img_comp->dy); + /*l_cstr_info->numcomps = p_j2k->m_image->numcomps; - l_img_comp->w = int_ceildivpow2(l_comp_x1, l_img_comp->factor) - int_ceildivpow2(l_img_comp->x0, l_img_comp->factor); - l_img_comp->h = int_ceildivpow2(l_comp_y1, l_img_comp->factor) - int_ceildivpow2(l_img_comp->y0, l_img_comp->factor); + l_cstr_info->numlayers = (&p_j2k->m_cp.tcps[0])->numlayers; - l_img_comp++; - } + l_cstr_info->numdecompos = (OPJ_INT32*) opj_malloc(p_j2k->m_image->numcomps * sizeof(OPJ_INT32)); - /* Destroy the previous output image*/ - if (p_j2k->m_output_image) - opj_image_destroy(p_j2k->m_output_image); + for (compno=0; compno < p_j2k->m_image->numcomps; compno++) { + l_cstr_info->numdecompos[compno] = (&p_j2k->m_cp.tcps[0])->tccps->numresolutions - 1; + } - /* Create the ouput image from the information previously computed*/ - 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); + l_cstr_info->D_max = 0.0; */ /* ADD Marcela */ - p_j2k->m_specific_param.m_decoder.m_tile_ind_to_dec = tile_index; + /*l_cstr_info->main_head_start = opj_stream_tell(p_stream);*/ /* position of SOC */ - /* customization of the decoding */ - j2k_setup_decoding_tile(p_j2k); + /*l_cstr_info->maxmarknum = 100; + l_cstr_info->marker = (opj_marker_info_t *) opj_malloc(l_cstr_info->maxmarknum * sizeof(opj_marker_info_t)); + l_cstr_info->marknum = 0; + }*/ - /* Decode the codestream */ - if (! j2k_exec (p_j2k,p_j2k->m_procedure_list,p_stream,p_manager)) { - opj_image_destroy(p_j2k->m_private_image); - p_j2k->m_private_image = NULL; - return OPJ_FALSE; - } + return j2k_calculate_tp_v2(p_j2k,&(p_j2k->m_cp),&p_j2k->m_specific_param.m_encoder.m_total_tile_parts,p_j2k->m_private_image,p_manager); +} - /* 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; +/** + * Creates a tile-coder decoder. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +opj_bool j2k_create_tcd(opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) +{ + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); - if (p_image->comps[compno].data) - opj_free(p_image->comps[compno].data); + p_j2k->m_tcd = tcd_create_v2(OPJ_FALSE); - p_image->comps[compno].data = p_j2k->m_output_image->comps[compno].data; + if (! p_j2k->m_tcd) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Not enough memory to create Tile Coder\n"); + return OPJ_FALSE; + } - p_j2k->m_output_image->comps[compno].data = NULL; + if (! tcd_init_v2(p_j2k->m_tcd,p_j2k->m_private_image,&p_j2k->m_cp)) { + tcd_destroy_v2(p_j2k->m_tcd); + p_j2k->m_tcd = 00; + return OPJ_FALSE; } return OPJ_TRUE; } -opj_bool j2k_set_decoded_resolution_factor(opj_j2k_v2_t *p_j2k, OPJ_UINT32 res_factor, opj_event_mgr_t * p_manager) -{ - OPJ_UINT32 it_comp; - - p_j2k->m_cp.m_specific_param.m_dec.m_reduce = res_factor; - if (p_j2k->m_private_image) { - if (p_j2k->m_private_image->comps) { - if (p_j2k->m_specific_param.m_decoder.m_default_tcp) { - if (p_j2k->m_specific_param.m_decoder.m_default_tcp->tccps) { - for (it_comp = 0 ; it_comp < p_j2k->m_private_image->numcomps; it_comp++) { - OPJ_UINT32 max_res = p_j2k->m_specific_param.m_decoder.m_default_tcp->tccps[it_comp].numresolutions; - if ( res_factor >= max_res){ - opj_event_msg_v2(p_manager, EVT_ERROR, "Resolution factor is superior to the maximum resolution in the component.\n"); - return OPJ_FALSE; - } - p_j2k->m_private_image->comps[it_comp].factor = res_factor; - } - return OPJ_TRUE; - } - } +/** + * Writes a tile. + * @param p_j2k the jpeg2000 codec. + * @param p_stream the stream to write data to. + * @param p_manager the user event manager. + */ +opj_bool j2k_write_tile (opj_j2k_v2_t * p_j2k, + OPJ_UINT32 p_tile_index, + OPJ_BYTE * p_data, + OPJ_UINT32 p_data_size, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ) +{ + if (! j2k_pre_write_tile(p_j2k,p_tile_index,p_stream,p_manager)) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error while j2k_pre_write_tile with tile index = %d\n", p_tile_index); + return OPJ_FALSE; + } + else { + if (! j2k_post_write_tile(p_j2k,p_data,p_data_size,p_stream,p_manager)) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error while j2k_post_write_tile with tile index = %d\n", p_tile_index); + return OPJ_FALSE; } } - return OPJ_FALSE; + return OPJ_TRUE; }