diff --git a/CHANGES b/CHANGES index 5d1f188d..2f296787 100644 --- a/CHANGES +++ b/CHANGES @@ -5,6 +5,9 @@ What's New for OpenJPEG ! : changed + : added +September 19, 2011 ++ [mickael] Work In Progress: insert elements from V2 framework into the trunk. + September 9, 2011 + [antonin] added a new indexer functionality to the library. With the new '-jpip' option at encoding, the user can now generate a JP2 file including an XML box with the index used when browsing the image with JPIP. diff --git a/applications/codec/j2k_dump.c b/applications/codec/j2k_dump.c index b490f4d4..1c1e8620 100644 --- a/applications/codec/j2k_dump.c +++ b/applications/codec/j2k_dump.c @@ -93,9 +93,9 @@ void decode_help_display(void) { fprintf(stdout," Currently accepts J2K-files, JP2-files and JPT-files. The file type\n"); fprintf(stdout," is identified based on its suffix.\n"); fprintf(stdout," -o \n"); - fprintf(stdout," OPTIONAL\n"); - fprintf(stdout," Output file where file info will be dump.\n"); - fprintf(stdout," By default it will be in the stdout.\n"); + fprintf(stdout," OPTIONAL\n"); + fprintf(stdout," Output file where file info will be dump.\n"); + fprintf(stdout," By default it will be in the stdout.\n"); fprintf(stdout,"\n"); } @@ -317,26 +317,30 @@ void info_callback(const char *msg, void *client_data) { int main(int argc, char *argv[]) { + int ret; opj_dparameters_t parameters; /* decompression parameters */ img_fol_t img_fol; opj_event_mgr_t event_mgr; /* event manager */ opj_image_t *image = NULL; FILE *fsrc = NULL, *fout = NULL; - unsigned char *src = NULL; - int file_length; + opj_bool bResult; int num_images; int i,imageno; dircnt_t *dirptr = NULL; - opj_dinfo_t* dinfo = NULL; /* handle to a decompressor */ - opj_cio_t *cio = NULL; + opj_codec_t* dinfo = NULL; /* handle to a decompressor */ + opj_stream_t *cio = NULL; opj_codestream_info_t cstr_info; /* Codestream information structure */ char indexfilename[OPJ_PATH_LEN]; /* index file name */ + OPJ_INT32 l_tile_x0,l_tile_y0; + OPJ_UINT32 l_tile_width,l_tile_height,l_nb_tiles_x,l_nb_tiles_y; - /* configure the event callbacks (not required) */ + + /* FIXME configure the event callbacks (not required) */ memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); event_mgr.error_handler = error_callback; event_mgr.warning_handler = warning_callback; event_mgr.info_handler = info_callback; + event_mgr.client_data = stderr; /* set decoding parameters to default values */ opj_set_default_decoder_parameters(¶meters); @@ -347,7 +351,7 @@ int main(int argc, char *argv[]) /* parse input and get user encoding parameters */ if(parse_cmdline_decoder(argc, argv, ¶meters,&img_fol, indexfilename) == 1) { - return 1; + return EXIT_FAILURE; } /* Initialize reading of directory */ @@ -360,39 +364,36 @@ int main(int argc, char *argv[]) dirptr->filename = (char**) malloc(num_images*sizeof(char*)); if(!dirptr->filename_buf){ - return 1; + return EXIT_FAILURE; } for(i=0;ifilename[i] = dirptr->filename_buf + i*OPJ_PATH_LEN; } } if(load_images(dirptr,img_fol.imgdirpath)==1){ - return 1; + return EXIT_FAILURE; } if (num_images==0){ fprintf(stdout,"Folder is empty\n"); - return 1; + return EXIT_FAILURE; } }else{ num_images=1; } // - if (parameters.outfile[0] != 0) - { - fout = fopen(parameters.outfile,"w"); - if (!fout) - { - fprintf(stderr, "ERROR -> failed to open %s for reading\n", parameters.outfile); - return 1; - } - } + if (parameters.outfile[0] != 0){ + fout = fopen(parameters.outfile,"w"); + if (!fout){ + fprintf(stderr, "ERROR -> failed to open %s for reading\n", parameters.outfile); + return EXIT_FAILURE; + } + } else - fout = stdout; + fout = stdout; /*Encoding image one by one*/ - for(imageno = 0; imageno < num_images ; imageno++) - { + for(imageno = 0; imageno < num_images ; imageno++){ image = NULL; fprintf(stderr,"\n"); @@ -403,182 +404,118 @@ int main(int argc, char *argv[]) } } +/*NEW V2 STYLE*/ /* read the input file and put it in memory */ /* ---------------------------------------- */ fsrc = fopen(parameters.infile, "rb"); if (!fsrc) { fprintf(stderr, "ERROR -> failed to open %s for reading\n", parameters.infile); - return 1; + return EXIT_FAILURE; } - fseek(fsrc, 0, SEEK_END); - file_length = ftell(fsrc); - fseek(fsrc, 0, SEEK_SET); - src = (unsigned char *) malloc(file_length); - if (fread(src, 1, file_length, fsrc) != (size_t)file_length) - { - free(src); - fclose(fsrc); - fprintf(stderr, "\nERROR: fread return a number of element different from the expected.\n"); - return 1; - } - fclose(fsrc); + + + cio = opj_stream_create_default_file_stream(fsrc,1); + /* decode the code-stream */ /* ---------------------- */ switch(parameters.decod_format) { - case J2K_CFMT: - { - /* JPEG-2000 codestream */ + case J2K_CFMT: + { /* JPEG-2000 codestream */ - /* get a decoder handle */ - dinfo = opj_create_decompress(CODEC_J2K); + /* get a decoder handle */ + dinfo = opj_create_decompress_v2(CODEC_J2K); + break; + } + case JP2_CFMT: + { /* JPEG 2000 compressed image data */ - /* catch events using our callbacks and give a local context */ - opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); + /* get a decoder handle */ + dinfo = opj_create_decompress_v2(CODEC_JP2); + break; + } + case JPT_CFMT: + { /* JPEG 2000, JPIP */ - /* setup the decoder decoding parameters using user parameters */ - opj_setup_decoder(dinfo, ¶meters); + /* get a decoder handle */ + dinfo = opj_create_decompress_v2(CODEC_JPT); + break; + } + default: + fprintf(stderr, "skipping file..\n"); + opj_stream_destroy(cio); + continue; + } - /* open a byte stream */ - cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length); + /* FIXME catch events using our callbacks and give a local context */ + //opj_set_event_mgr_v2(dinfo, &event_mgr, stderr); - /* decode the stream and fill the image structure */ - if (*indexfilename) // If need to extract codestream information + + + /* setup the decoder decoding parameters using user parameters */ + opj_setup_decoder_v2(dinfo, ¶meters, &event_mgr); + + /* decode the stream and fill the image structure */ + /* if (*indexfilename) // If need to extract codestream information image = opj_decode_with_info(dinfo, cio, &cstr_info); else - image = opj_decode(dinfo, cio); - if(!image) { - fprintf(stderr, "ERROR -> j2k_to_image: failed to decode image!\n"); - opj_destroy_decompress(dinfo); - opj_cio_close(cio); - return 1; - } + */ + bResult = opj_read_header( dinfo, + &image, + &l_tile_x0, + &l_tile_y0, + &l_tile_width, + &l_tile_height, + &l_nb_tiles_x, + &l_nb_tiles_y, + cio); + + if(!bResult){ + fprintf(stderr, "ERROR -> j2k_to_image: failed to read header\n"); + return EXIT_FAILURE; + } + + if (parameters.decod_format == J2K_CFMT){ /* dump image */ - j2k_dump_image(fout, image); - + j2k_dump_image(fout, image); /* dump cp */ - j2k_dump_cp(fout, image, ((opj_j2k_t*)dinfo->j2k_handle)->cp); - - /* close the byte stream */ - opj_cio_close(cio); - - /* Write the index to disk */ - if (*indexfilename) { - opj_bool bSuccess; - bSuccess = write_index_file(&cstr_info, indexfilename); - if (bSuccess) { - fprintf(stderr, "Failed to output index file\n"); - } - } + //j2k_dump_cp(stdout, image, dinfo->m_codec); + //j2k_dump_cp(fout, image, ((opj_j2k_t*)dinfo->j2k_handle)->cp); } - break; - - case JP2_CFMT: - { - /* JPEG 2000 compressed image data */ - - /* get a decoder handle */ - dinfo = opj_create_decompress(CODEC_JP2); - - /* catch events using our callbacks and give a local context */ - opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); - - /* setup the decoder decoding parameters using the current image and user parameters */ - opj_setup_decoder(dinfo, ¶meters); - - /* open a byte stream */ - cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length); - - /* decode the stream and fill the image structure */ - if (*indexfilename) // If need to extract codestream information - image = opj_decode_with_info(dinfo, cio, &cstr_info); - else - image = opj_decode(dinfo, cio); - if(!image) { - fprintf(stderr, "ERROR -> j2k_to_image: failed to decode image!\n"); - opj_destroy_decompress(dinfo); - opj_cio_close(cio); - return 1; - } + else if (parameters.decod_format == JP2_CFMT){ /* dump image */ - if(image->icc_profile_buf) - { - free(image->icc_profile_buf); image->icc_profile_buf = NULL; - } - j2k_dump_image(fout, image); - + if(image->icc_profile_buf){ + free(image->icc_profile_buf); + image->icc_profile_buf = NULL; + } + j2k_dump_image(fout, image); /* dump cp */ - j2k_dump_cp(fout, image, ((opj_jp2_t*)dinfo->jp2_handle)->j2k->cp); - - /* close the byte stream */ - opj_cio_close(cio); - - /* Write the index to disk */ - if (*indexfilename) { - opj_bool bSuccess; - bSuccess = write_index_file(&cstr_info, indexfilename); - if (bSuccess) { - fprintf(stderr, "Failed to output index file\n"); - } - } + //j2k_dump_cp(stdout, image, dinfo->m_codec); + //j2k_dump_cp(fout, image, ((opj_jp2_t*)dinfo->jp2_handle)->j2k->cp); } - break; - case JPT_CFMT: - { - /* JPEG 2000, JPIP */ + /* close the byte stream */ + opj_stream_destroy(cio); + fclose(fsrc); - /* get a decoder handle */ - dinfo = opj_create_decompress(CODEC_JPT); - - /* catch events using our callbacks and give a local context */ - opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); - - /* setup the decoder decoding parameters using user parameters */ - opj_setup_decoder(dinfo, ¶meters); - - /* open a byte stream */ - cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length); - - /* decode the stream and fill the image structure */ - if (*indexfilename) // If need to extract codestream information - image = opj_decode_with_info(dinfo, cio, &cstr_info); + /* Write the index to disk */ + if (*indexfilename) { + char bSuccess; + bSuccess = write_index_file(&cstr_info, indexfilename); + if (bSuccess) { + fprintf(stderr, "Failed to output index file\n"); + ret = EXIT_FAILURE; + } else - image = opj_decode(dinfo, cio); - if(!image) { - fprintf(stderr, "ERROR -> j2k_to_image: failed to decode image!\n"); - opj_destroy_decompress(dinfo); - opj_cio_close(cio); - return 1; - } - - /* close the byte stream */ - opj_cio_close(cio); - - /* Write the index to disk */ - if (*indexfilename) { - opj_bool bSuccess; - bSuccess = write_index_file(&cstr_info, indexfilename); - if (bSuccess) { - fprintf(stderr, "Failed to output index file\n"); - } - } + ret = EXIT_SUCCESS; } - break; - - default: - fprintf(stderr, "skipping file..\n"); - continue; - } - - /* free the memory containing the code-stream */ - free(src); - src = NULL; + else + ret = EXIT_SUCCESS; /* free remaining structures */ - if(dinfo) { - opj_destroy_decompress(dinfo); + if (dinfo) { + opj_destroy_codec(dinfo); } /* free codestream information structure */ if (*indexfilename) @@ -587,10 +524,11 @@ int main(int argc, char *argv[]) opj_image_destroy(image); } +/*NEW V2 STYLE*/ fclose(fout); - return EXIT_SUCCESS; + return ret; } @@ -662,9 +600,9 @@ static void j2k_dump_cp(FILE *fd, opj_image_t * img, opj_cp_t * cp) { fprintf(fd, "\n"); } fprintf(fd, " }\n"); - } + } /*end of component*/ fprintf(fd, " }\n"); - } + } /*end of tile */ fprintf(fd, "}\n"); } diff --git a/libopenjpeg/CMakeLists.txt b/libopenjpeg/CMakeLists.txt index c51e2d29..24ecf409 100644 --- a/libopenjpeg/CMakeLists.txt +++ b/libopenjpeg/CMakeLists.txt @@ -24,6 +24,7 @@ SET(OPENJPEG_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/ppix_manager.c ${CMAKE_CURRENT_SOURCE_DIR}/thix_manager.c ${CMAKE_CURRENT_SOURCE_DIR}/tpix_manager.c + ${CMAKE_CURRENT_SOURCE_DIR}/function_list.c ) # Build the library diff --git a/libopenjpeg/cio.c b/libopenjpeg/cio.c index b8a7ecf8..2c5dec9f 100644 --- a/libopenjpeg/cio.c +++ b/libopenjpeg/cio.c @@ -188,4 +188,790 @@ void cio_skip(opj_cio_t *cio, int n) { } +/* ----------------------------------------------------------------------- */ + + +/** + * Write some bytes to the given data buffer, this function is used in Big Endian cpus. + * @param p_buffer pointer the data buffer to write data to. + * @param p_value the value to write + * @param p_nb_bytes the number of bytes to write +*/ +void opj_write_bytes_BE (OPJ_BYTE * p_buffer, OPJ_UINT32 p_value, OPJ_UINT32 p_nb_bytes) +{ + const OPJ_BYTE * l_data_ptr = ((const OPJ_BYTE *) &p_value) + p_nb_bytes; + + assert(p_nb_bytes > 0 && p_nb_bytes <= sizeof(OPJ_UINT32)); + + memcpy(p_buffer,l_data_ptr,p_nb_bytes); +} + +/** + * Write some bytes to the given data buffer, this function is used in Little Endian cpus. + * @param p_buffer pointer the data buffer to write data to. + * @param p_value the value to write + * @param p_nb_bytes the number of bytes to write + * @return the number of bytes written or -1 if an error occured +*/ +void opj_write_bytes_LE (OPJ_BYTE * p_buffer, OPJ_UINT32 p_value, OPJ_UINT32 p_nb_bytes) +{ + const OPJ_BYTE * l_data_ptr = ((const OPJ_BYTE *) &p_value) + p_nb_bytes - 1; + OPJ_UINT32 i; + + assert(p_nb_bytes > 0 && p_nb_bytes <= sizeof(OPJ_UINT32)); + + for (i=0;i 0 && p_nb_bytes <= sizeof(OPJ_UINT32)); + + *p_value = 0; + memcpy(l_data_ptr+4-p_nb_bytes,p_buffer,p_nb_bytes); +} + +/** + * Reads some bytes from the given data buffer, this function is used in Little Endian cpus. + * @param p_buffer pointer the data buffer to read data from. + * @param p_value pointer to the value that will store the data. + * @param p_nb_bytes the nb bytes to read. + * @return the number of bytes read or -1 if an error occured. + */ +void opj_read_bytes_LE(const OPJ_BYTE * p_buffer, OPJ_UINT32 * p_value, OPJ_UINT32 p_nb_bytes) +{ + OPJ_BYTE * l_data_ptr = ((OPJ_BYTE *) p_value) + p_nb_bytes-1; + OPJ_UINT32 i; + + assert(p_nb_bytes > 0 && p_nb_bytes <= sizeof(OPJ_UINT32)); + + *p_value = 0; + for (i=0;im_buffer_size = p_size; + l_stream->m_stored_data = (OPJ_BYTE *) opj_malloc(p_size); + if (! l_stream->m_stored_data) { + opj_free(l_stream); + return 00; + } + + l_stream->m_current_data = l_stream->m_stored_data; + + if (l_is_input) { + l_stream->m_status |= opj_stream_e_input; + l_stream->m_opj_skip = opj_stream_read_skip; + l_stream->m_opj_seek = opj_stream_read_seek; + } + else { + l_stream->m_status |= opj_stream_e_output; + l_stream->m_opj_skip = opj_stream_write_skip; + l_stream->m_opj_seek = opj_stream_write_seek; + } + + l_stream->m_read_fn = opj_stream_default_read; + l_stream->m_write_fn = opj_stream_default_write; + l_stream->m_skip_fn = opj_stream_default_skip; + l_stream->m_seek_fn = opj_stream_default_seek; + + return (opj_stream_t *) l_stream; +} + +/** + * Creates an abstract stream. This function does nothing except allocating memory and initializing the abstract stream. + * @return a stream object. +*/ +opj_stream_t* OPJ_CALLCONV opj_stream_default_create(opj_bool l_is_input) +{ + return opj_stream_create(J2K_STREAM_CHUNK_SIZE,l_is_input); +} + +/** + * Destroys a stream created by opj_create_stream. This function does NOT close the abstract stream. If needed the user must + * close its own implementation of the stream. + */ +OPJ_API void OPJ_CALLCONV opj_stream_destroy(opj_stream_t* p_stream) +{ + opj_stream_private_t* l_stream = (opj_stream_private_t*) p_stream; + if (l_stream) { + opj_free(l_stream->m_stored_data); + l_stream->m_stored_data = 00; + opj_free(l_stream); + } +} + +/** + * Sets the given function to be used as a read function. + * @param p_stream the stream to modify + * @param p_function the function to use a read function. +*/ +OPJ_API void OPJ_CALLCONV opj_stream_set_read_function(opj_stream_t* p_stream, opj_stream_read_fn p_function) +{ + opj_stream_private_t* l_stream = (opj_stream_private_t*) p_stream; + if + ((!l_stream) || (! (l_stream->m_status & opj_stream_e_input))) + { + return; + } + l_stream->m_read_fn = p_function; +} + +OPJ_API void OPJ_CALLCONV opj_stream_set_seek_function(opj_stream_t* p_stream, opj_stream_seek_fn p_function) +{ + opj_stream_private_t* l_stream = (opj_stream_private_t*) p_stream; + if + (!l_stream) + { + return; + } + l_stream->m_seek_fn = p_function; +} + +/** + * Sets the given function to be used as a write function. + * @param p_stream the stream to modify + * @param p_function the function to use a write function. +*/ +OPJ_API void OPJ_CALLCONV opj_stream_set_write_function(opj_stream_t* p_stream, opj_stream_write_fn p_function) +{ + opj_stream_private_t* l_stream = (opj_stream_private_t*) p_stream; + if + ((!l_stream )|| (! (l_stream->m_status & opj_stream_e_output))) + { + return; + } + l_stream->m_write_fn = p_function; +} + +/** + * Sets the given function to be used as a skip function. + * @param p_stream the stream to modify + * @param p_function the function to use a skip function. +*/ +OPJ_API void OPJ_CALLCONV opj_stream_set_skip_function(opj_stream_t* p_stream, opj_stream_skip_fn p_function) +{ + opj_stream_private_t* l_stream = (opj_stream_private_t*) p_stream; + if + (! l_stream) + { + return; + } + l_stream->m_skip_fn = p_function; +} + +/** + * Sets the given data to be used as a user data for the stream. + * @param p_stream the stream to modify + * @param p_data the data to set. +*/ +OPJ_API void OPJ_CALLCONV opj_stream_set_user_data(opj_stream_t* p_stream, void * p_data) +{ + opj_stream_private_t* l_stream = (opj_stream_private_t*) p_stream; + l_stream->m_user_data = p_data; +} + +/** + * Reads some bytes from the stream. + * @param p_stream the stream to read data from. + * @param p_buffer pointer to the data buffer that will receive the data. + * @param p_size number of bytes to read. + * @param p_event_mgr the user event manager to be notified of special events. + * @return the number of bytes read, or -1 if an error occured or if the stream is at the end. + */ +OPJ_UINT32 opj_stream_read_data (opj_stream_private_t * p_stream,OPJ_BYTE * p_buffer, OPJ_UINT32 p_size, opj_event_mgr_t * p_event_mgr) +{ + OPJ_UINT32 l_read_nb_bytes = 0; + if + (p_stream->m_bytes_in_buffer >= p_size) + { + memcpy(p_buffer,p_stream->m_current_data,p_size); + p_stream->m_current_data += p_size; + p_stream->m_bytes_in_buffer -= p_size; + l_read_nb_bytes += p_size; + p_stream->m_byte_offset += p_size; + return l_read_nb_bytes; + } + + // we are now in the case when the remaining data if not sufficient + if + (p_stream->m_status & opj_stream_e_end) + { + l_read_nb_bytes += p_stream->m_bytes_in_buffer; + memcpy(p_buffer,p_stream->m_current_data,p_stream->m_bytes_in_buffer); + p_stream->m_current_data += p_stream->m_bytes_in_buffer; + p_stream->m_byte_offset += p_stream->m_bytes_in_buffer; + p_stream->m_bytes_in_buffer = 0; + return l_read_nb_bytes ? l_read_nb_bytes : -1; + } + + // the flag is not set, we copy data and then do an actual read on the stream + if + (p_stream->m_bytes_in_buffer) + { + l_read_nb_bytes += p_stream->m_bytes_in_buffer; + memcpy(p_buffer,p_stream->m_current_data,p_stream->m_bytes_in_buffer); + p_stream->m_current_data = p_stream->m_stored_data; + p_buffer += p_stream->m_bytes_in_buffer; + p_size -= p_stream->m_bytes_in_buffer; + p_stream->m_byte_offset += p_stream->m_bytes_in_buffer; + p_stream->m_bytes_in_buffer = 0; + } + else + { + /* case where we are already at the end of the buffer + so reset the m_current_data to point to the start of the + stored buffer to get ready to read from disk*/ + p_stream->m_current_data = p_stream->m_stored_data; + } + + + while(1){ + // we should read less than a chunk -> read a chunk + if + (p_size < p_stream->m_buffer_size) + { + // we should do an actual read on the media + p_stream->m_bytes_in_buffer = p_stream->m_read_fn(p_stream->m_stored_data,p_stream->m_buffer_size,p_stream->m_user_data); + if + (p_stream->m_bytes_in_buffer == -1) + { + // end of stream +#ifdef TODO_MSD + opj_event_msg(p_event_mgr, EVT_INFO, "Stream reached its end !\n"); +#endif + p_stream->m_bytes_in_buffer = 0; + p_stream->m_status |= opj_stream_e_end; + // end of stream + return l_read_nb_bytes ? l_read_nb_bytes : -1; + } + else if + (p_stream->m_bytes_in_buffer < p_size) + { + // not enough data + l_read_nb_bytes += p_stream->m_bytes_in_buffer; + memcpy(p_buffer,p_stream->m_current_data,p_stream->m_bytes_in_buffer); + p_stream->m_current_data = p_stream->m_stored_data; + p_buffer += p_stream->m_bytes_in_buffer; + p_size -= p_stream->m_bytes_in_buffer; + p_stream->m_byte_offset += p_stream->m_bytes_in_buffer; + p_stream->m_bytes_in_buffer = 0; + } + else + { + l_read_nb_bytes += p_size; + memcpy(p_buffer,p_stream->m_current_data,p_size); + p_stream->m_current_data += p_size; + p_stream->m_bytes_in_buffer -= p_size; + p_stream->m_byte_offset += p_size; + return l_read_nb_bytes; + } + } + else + { + // direct read on the dest buffer + p_stream->m_bytes_in_buffer = p_stream->m_read_fn(p_buffer,p_size,p_stream->m_user_data); + if + (p_stream->m_bytes_in_buffer == -1) + { + // end of stream +#ifdef TODO_MSD + opj_event_msg(p_event_mgr, EVT_INFO, "Stream reached its end !\n"); +#endif + p_stream->m_bytes_in_buffer = 0; + p_stream->m_status |= opj_stream_e_end; + // end of stream + return l_read_nb_bytes ? l_read_nb_bytes : -1; + } + else if + (p_stream->m_bytes_in_buffer < p_size) + { + // not enough data + l_read_nb_bytes += p_stream->m_bytes_in_buffer; + p_stream->m_current_data = p_stream->m_stored_data; + p_buffer += p_stream->m_bytes_in_buffer; + p_size -= p_stream->m_bytes_in_buffer; + p_stream->m_byte_offset += p_stream->m_bytes_in_buffer; + p_stream->m_bytes_in_buffer = 0; + } + else + { + // we have read the exact size + l_read_nb_bytes += p_stream->m_bytes_in_buffer; + p_stream->m_byte_offset += p_stream->m_bytes_in_buffer; + p_stream->m_current_data = p_stream->m_stored_data; + p_stream->m_bytes_in_buffer = 0; + return l_read_nb_bytes; + } + } + } +} + +/** + * Writes some bytes from the stream. + * @param p_stream the stream to write data to. + * @param p_buffer pointer to the data buffer holds the data to be writtent. + * @param p_size number of bytes to write. + * @param p_event_mgr the user event manager to be notified of special events. + * @return the number of bytes writtent, or -1 if an error occured. + */ +OPJ_UINT32 opj_stream_write_data (opj_stream_private_t * p_stream,const OPJ_BYTE * p_buffer,OPJ_UINT32 p_size, opj_event_mgr_t * p_event_mgr) +{ + OPJ_UINT32 l_remaining_bytes = 0; + OPJ_UINT32 l_write_nb_bytes = 0; + + if + (p_stream->m_status & opj_stream_e_error) + { + return -1; + } + + while(1) + { + l_remaining_bytes = p_stream->m_buffer_size - p_stream->m_bytes_in_buffer; + // we have more memory than required + if + (l_remaining_bytes >= p_size) + { + memcpy(p_stream->m_current_data,p_buffer,p_size); + p_stream->m_current_data += p_size; + p_stream->m_bytes_in_buffer += p_size; + l_write_nb_bytes += p_size; + p_stream->m_byte_offset += p_size; + return l_write_nb_bytes; + } + + // we copy data and then do an actual read on the stream + if + (l_remaining_bytes) + { + l_write_nb_bytes += l_remaining_bytes; + memcpy(p_stream->m_current_data,p_buffer,l_remaining_bytes); + p_stream->m_current_data = p_stream->m_stored_data; + p_buffer += l_remaining_bytes; + p_size -= l_remaining_bytes; + p_stream->m_bytes_in_buffer += l_remaining_bytes; + p_stream->m_byte_offset += l_remaining_bytes; + } + if + (! opj_stream_flush(p_stream, p_event_mgr)) + { + return -1; + } + } + +} + +/** + * Writes the content of the stream buffer to the stream. + * @param p_stream the stream to write data to. + * @param p_event_mgr the user event manager to be notified of special events. + * @return the number of bytes written, or -1 if an error occured. + */ +opj_bool opj_stream_flush (opj_stream_private_t * p_stream, opj_event_mgr_t * p_event_mgr) +{ + // the number of bytes written on the media. + OPJ_UINT32 l_current_write_nb_bytes = 0; + p_stream->m_current_data = p_stream->m_stored_data; + + while + (p_stream->m_bytes_in_buffer) + { + // we should do an actual write on the media + l_current_write_nb_bytes = p_stream->m_write_fn(p_stream->m_current_data,p_stream->m_bytes_in_buffer,p_stream->m_user_data); + if + (l_current_write_nb_bytes == -1) + { + p_stream->m_status |= opj_stream_e_error; +#ifdef TODO_MSD + opj_event_msg(p_event_mgr, EVT_INFO, "Error on writting stream!\n"); +#endif + return EXIT_FAILURE; + } + p_stream->m_current_data += l_current_write_nb_bytes; + p_stream->m_bytes_in_buffer -= l_current_write_nb_bytes; + } + p_stream->m_current_data = p_stream->m_stored_data; + return EXIT_SUCCESS; +} + +/** + * Skips a number of bytes from the stream. + * @param p_stream the stream to skip data from. + * @param p_size the number of bytes to skip. + * @param p_event_mgr the user event manager to be notified of special events. + * @return the number of bytes skipped, or -1 if an error occured. + */ +OPJ_SIZE_T opj_stream_read_skip (opj_stream_private_t * p_stream, OPJ_SIZE_T p_size, opj_event_mgr_t * p_event_mgr) +{ + OPJ_SIZE_T l_skip_nb_bytes = 0; + OPJ_SIZE_T l_current_skip_nb_bytes = 0; + + if + (p_stream->m_bytes_in_buffer >= p_size) + { + p_stream->m_current_data += p_size; + p_stream->m_bytes_in_buffer -= p_size; + l_skip_nb_bytes += p_size; + p_stream->m_byte_offset += l_skip_nb_bytes; + return l_skip_nb_bytes; + } + + // we are now in the case when the remaining data if not sufficient + if + (p_stream->m_status & opj_stream_e_end) + { + l_skip_nb_bytes += p_stream->m_bytes_in_buffer; + p_stream->m_current_data += p_stream->m_bytes_in_buffer; + p_stream->m_bytes_in_buffer = 0; + p_stream->m_byte_offset += l_skip_nb_bytes; + return l_skip_nb_bytes ? l_skip_nb_bytes : (OPJ_SIZE_T) -1; + } + + // the flag is not set, we copy data and then do an actual skip on the stream + if + (p_stream->m_bytes_in_buffer) + { + l_skip_nb_bytes += p_stream->m_bytes_in_buffer; + p_stream->m_current_data = p_stream->m_stored_data; + p_size -= p_stream->m_bytes_in_buffer; + p_stream->m_bytes_in_buffer = 0; + } + + while + (p_size > 0) + { + // we should do an actual skip on the media + l_current_skip_nb_bytes = p_stream->m_skip_fn(p_size, p_stream->m_user_data); + if + (l_current_skip_nb_bytes == (OPJ_SIZE_T) -1) + { +#ifdef TODO_MSD + opj_event_msg(p_event_mgr, EVT_INFO, "Stream reached its end !\n"); +# endif + p_stream->m_status |= opj_stream_e_end; + p_stream->m_byte_offset += l_skip_nb_bytes; + // end if stream + return l_skip_nb_bytes ? l_skip_nb_bytes : (OPJ_SIZE_T) -1; + } + p_size -= l_current_skip_nb_bytes; + l_skip_nb_bytes += l_current_skip_nb_bytes; + } + p_stream->m_byte_offset += l_skip_nb_bytes; + return l_skip_nb_bytes; +} + +/** + * Skips a number of bytes from the stream. + * @param p_stream the stream to skip data from. + * @param p_size the number of bytes to skip. + * @param p_event_mgr the user event manager to be notified of special events. + * @return the number of bytes skipped, or -1 if an error occured. + */ +OPJ_SIZE_T opj_stream_write_skip (opj_stream_private_t * p_stream, OPJ_SIZE_T p_size, opj_event_mgr_t * p_event_mgr) +{ + opj_bool l_is_written = 0; + OPJ_SIZE_T l_current_skip_nb_bytes = 0; + OPJ_SIZE_T l_skip_nb_bytes = 0; + + if + (p_stream->m_status & opj_stream_e_error) + { + return (OPJ_SIZE_T) -1; + } + + // we should flush data + l_is_written = opj_stream_flush (p_stream, p_event_mgr); + if + (! l_is_written) + { + p_stream->m_status |= opj_stream_e_error; + p_stream->m_bytes_in_buffer = 0; + p_stream->m_current_data = p_stream->m_current_data; + return (OPJ_SIZE_T) -1; + } + // then skip + + while + (p_size > 0) + { + // we should do an actual skip on the media + l_current_skip_nb_bytes = p_stream->m_skip_fn(p_size, p_stream->m_user_data); + if + (l_current_skip_nb_bytes == (OPJ_SIZE_T)-1) + { +#ifdef TODO_MSD + opj_event_msg(p_event_mgr, EVT_INFO, "Stream error!\n"); +#endif + p_stream->m_status |= opj_stream_e_error; + p_stream->m_byte_offset += l_skip_nb_bytes; + // end if stream + return l_skip_nb_bytes ? l_skip_nb_bytes : (OPJ_SIZE_T)-1; + } + p_size -= l_current_skip_nb_bytes; + l_skip_nb_bytes += l_current_skip_nb_bytes; + } + p_stream->m_byte_offset += l_skip_nb_bytes; + return l_skip_nb_bytes; +} + +/** + * Tells the byte offset on the stream (similar to ftell). + * + * @param p_stream the stream to get the information from. + * + * @return the current position of the stream. + */ +OPJ_SIZE_T opj_stream_tell (const opj_stream_private_t * p_stream) +{ + return p_stream->m_byte_offset; +} + +/** + * Skips a number of bytes from the stream. + * @param p_stream the stream to skip data from. + * @param p_size the number of bytes to skip. + * @param p_event_mgr the user event manager to be notified of special events. + * @return the number of bytes skipped, or -1 if an error occured. + */ +OPJ_SIZE_T opj_stream_skip (opj_stream_private_t * p_stream, OPJ_SIZE_T p_size, opj_event_mgr_t * p_event_mgr) +{ + return p_stream->m_opj_skip(p_stream,p_size,p_event_mgr); +} + + +/** + * Skips a number of bytes from the stream. + * @param p_stream the stream to skip data from. + * @param p_size the number of bytes to skip. + * @param p_event_mgr the user event manager to be notified of special events. + * @return the number of bytes skipped, or -1 if an error occured. + */ +opj_bool opj_stream_read_seek (opj_stream_private_t * p_stream, OPJ_SIZE_T p_size, opj_event_mgr_t * p_event_mgr) +{ + p_stream->m_current_data = p_stream->m_stored_data; + p_stream->m_bytes_in_buffer = 0; + if + (! p_stream->m_seek_fn(p_size,p_stream->m_user_data)) + { + p_stream->m_status |= opj_stream_e_end; + return EXIT_FAILURE; + } + else + { + // reset stream status + p_stream->m_status &= (~opj_stream_e_end); + p_stream->m_byte_offset = p_size; + + } + return EXIT_SUCCESS; +} + +/** + * Skips a number of bytes from the stream. + * @param p_stream the stream to skip data from. + * @param p_size the number of bytes to skip. + * @param p_event_mgr the user event manager to be notified of special events. + * @return the number of bytes skipped, or -1 if an error occured. + */ +opj_bool opj_stream_write_seek (opj_stream_private_t * p_stream, OPJ_SIZE_T p_size, opj_event_mgr_t * p_event_mgr) +{ + if + (! opj_stream_flush(p_stream,p_event_mgr)) + { + p_stream->m_status |= opj_stream_e_error; + return EXIT_FAILURE; + } + + p_stream->m_current_data = p_stream->m_stored_data; + p_stream->m_bytes_in_buffer = 0; + + if + (! p_stream->m_seek_fn(p_size,p_stream->m_user_data)) + { + p_stream->m_status |= opj_stream_e_error; + return EXIT_FAILURE; + } + else + { + p_stream->m_byte_offset = p_size; + } + return EXIT_SUCCESS; +} + + +/** + * Seeks a number of bytes from the stream. + * @param p_stream the stream to skip data from. + * @param p_size the number of bytes to skip. + * @param p_event_mgr the user event manager to be notified of special events. + * @return true if the stream is seekable. + */ +opj_bool opj_stream_seek (opj_stream_private_t * p_stream, OPJ_SIZE_T p_size, struct opj_event_mgr * p_event_mgr) +{ + return p_stream->m_opj_seek(p_stream,p_size,p_event_mgr); +} + +/** + * Tells if the given stream is seekable. + */ +opj_bool opj_stream_has_seek (const opj_stream_private_t * p_stream) +{ + return p_stream->m_seek_fn != opj_stream_default_seek; +} + + + + + +OPJ_UINT32 opj_stream_default_read (void * p_buffer, OPJ_UINT32 p_nb_bytes, void * p_user_data) +{ + return (OPJ_UINT32) -1; +} +OPJ_UINT32 opj_stream_default_write (void * p_buffer, OPJ_UINT32 p_nb_bytes, void * p_user_data) +{ + return (OPJ_UINT32) -1; +} +OPJ_SIZE_T opj_stream_default_skip (OPJ_SIZE_T p_nb_bytes, void * p_user_data) +{ + return (OPJ_SIZE_T) -1; +} + +opj_bool opj_stream_default_seek (OPJ_SIZE_T p_nb_bytes, void * p_user_data) +{ + return EXIT_FAILURE; +} + + + diff --git a/libopenjpeg/cio.h b/libopenjpeg/cio.h index ce1a13ec..ed95d5cd 100644 --- a/libopenjpeg/cio.h +++ b/libopenjpeg/cio.h @@ -41,6 +41,8 @@ The functions in CIO.C have for goal to realize a byte input / output process. /** @defgroup CIO CIO - byte input-output stream */ /*@{*/ +#include "opj_config.h" + /** @name Exported functions (see also openjpeg.h) */ /*@{*/ /* ----------------------------------------------------------------------- */ @@ -82,5 +84,312 @@ void cio_skip(opj_cio_t *cio, int n); /*@}*/ + + +/* ----------------------------------------------------------------------- */ + +#if defined(OPJ_BIG_ENDIAN) + #if !defined(OPJ_LITTLE_ENDIAN) + #define opj_write_bytes opj_write_bytes_BE + #define opj_read_bytes opj_read_bytes_BE + #define opj_write_double opj_write_double_BE + #define opj_read_double opj_read_double_BE + #define opj_write_float opj_write_float_BE + #define opj_read_float opj_read_float_BE + #else + #error "Either BIG_ENDIAN or LITTLE_ENDIAN must be #defined, but not both." + #endif +#else + #if defined(OPJ_LITTLE_ENDIAN) + #define opj_write_bytes opj_write_bytes_LE + #define opj_read_bytes opj_read_bytes_LE + #define opj_write_double opj_write_double_LE + #define opj_read_double opj_read_double_LE + #define opj_write_float opj_write_float_LE + #define opj_read_float opj_read_float_LE + #else + #error "Either BIG_ENDIAN or LITTLE_ENDIAN must be #defined, but not none." + #endif +#endif + + + +typedef enum +{ + opj_stream_e_output = 0x1, + opj_stream_e_input = 0x2, + opj_stream_e_end = 0x4, + opj_stream_e_error = 0x8 +} +opj_stream_flag ; + +/** +Byte input-output stream. +*/ +typedef struct opj_stream_private +{ + /** + * User data, be it files, ... The actual data depends on the type of the stream. + */ + void * m_user_data; + + /** + * Pointer to actual read function (NULL at the initialization of the cio. + */ + opj_stream_read_fn m_read_fn; + + /** + * Pointer to actual write function (NULL at the initialization of the cio. + */ + opj_stream_write_fn m_write_fn; + + /** + * Pointer to actual skip function (NULL at the initialization of the cio. + * There is no seek function to prevent from back and forth slow procedures. + */ + opj_stream_skip_fn m_skip_fn; + + /** + * Pointer to actual seek function (if available). + */ + opj_stream_seek_fn m_seek_fn; + + + + + /** + * Actual data stored into the stream if readed from. Data is read by chunk of fixed size. + * you should never access this data directly. + */ + OPJ_BYTE * m_stored_data; + + /** + * Pointer to the current read data. + */ + OPJ_BYTE * m_current_data; + + OPJ_SIZE_T (* m_opj_skip)(struct opj_stream_private * ,OPJ_SIZE_T , struct opj_event_mgr *); + + opj_bool (* m_opj_seek) (struct opj_stream_private * , OPJ_SIZE_T , struct opj_event_mgr *); + + /** + * number of bytes containing in the buffer. + */ + OPJ_UINT32 m_bytes_in_buffer; + + /** + * The number of bytes read/written. + */ + OPJ_SIZE_T m_byte_offset; + + /** + * The size of the buffer. + */ + OPJ_UINT32 m_buffer_size; + + /** + * Flags to tell the status of the stream. + */ + OPJ_UINT32 m_status; + +} +opj_stream_private_t; + + +/** + * Write some bytes to the given data buffer, this function is used in Big Endian cpus. + * @param p_buffer pointer the data buffer to write data to. + * @param p_value the value to write + * @param p_nb_bytes the number of bytes to write +*/ +void opj_write_bytes_BE (OPJ_BYTE * p_buffer, OPJ_UINT32 p_value, OPJ_UINT32 p_nb_bytes); + +/** + * Reads some bytes from the given data buffer, this function is used in Big Endian cpus. + * @param p_buffer pointer the data buffer to read data from. + * @param p_value pointer to the value that will store the data. + * @param p_nb_bytes the nb bytes to read. + * @return the number of bytes read or -1 if an error occured. + */ +void opj_read_bytes_BE(const OPJ_BYTE * p_buffer, OPJ_UINT32 * p_value, OPJ_UINT32 p_nb_bytes); + +/** + * Write some bytes to the given data buffer, this function is used in Little Endian cpus. + * @param p_buffer pointer the data buffer to write data to. + * @param p_value the value to write + * @param p_nb_bytes the number of bytes to write + * @return the number of bytes written or -1 if an error occured +*/ +void opj_write_bytes_LE (OPJ_BYTE * p_buffer, OPJ_UINT32 p_value, OPJ_UINT32 p_nb_bytes); + +/** + * Reads some bytes from the given data buffer, this function is used in Little Endian cpus. + * @param p_buffer pointer the data buffer to read data from. + * @param p_value pointer to the value that will store the data. + * @param p_nb_bytes the nb bytes to read. + * @return the number of bytes read or -1 if an error occured. + */ +void opj_read_bytes_LE(const OPJ_BYTE * p_buffer, OPJ_UINT32 * p_value, OPJ_UINT32 p_nb_bytes); + + +/** + * Write some bytes to the given data buffer, this function is used in Little Endian cpus. + * @param p_buffer pointer the data buffer to write data to. + * @param p_value the value to write + */ +void opj_write_double_LE(OPJ_BYTE * p_buffer, OPJ_FLOAT64 p_value); + +/*** + * Write some bytes to the given data buffer, this function is used in Big Endian cpus. + * @param p_buffer pointer the data buffer to write data to. + * @param p_value the value to write + */ +void opj_write_double_BE(OPJ_BYTE * p_buffer, OPJ_FLOAT64 p_value); + +/** + * Reads some bytes from the given data buffer, this function is used in Little Endian cpus. + * @param p_buffer pointer the data buffer to read data from. + * @param p_value pointer to the value that will store the data. + */ +void opj_read_double_LE(const OPJ_BYTE * p_buffer, OPJ_FLOAT64 * p_value); + +/** + * Reads some bytes from the given data buffer, this function is used in Big Endian cpus. + * @param p_buffer pointer the data buffer to read data from. + * @param p_value pointer to the value that will store the data. + */ +void opj_read_double_BE(const OPJ_BYTE * p_buffer, OPJ_FLOAT64 * p_value); + +/** + * Reads some bytes from the given data buffer, this function is used in Little Endian cpus. + * @param p_buffer pointer the data buffer to read data from. + * @param p_value pointer to the value that will store the data. + */ +void opj_read_float_LE(const OPJ_BYTE * p_buffer, OPJ_FLOAT32 * p_value); + +/** + * Reads some bytes from the given data buffer, this function is used in Big Endian cpus. + * @param p_buffer pointer the data buffer to read data from. + * @param p_value pointer to the value that will store the data. + */ +void opj_read_float_BE(const OPJ_BYTE * p_buffer, OPJ_FLOAT32 * p_value); + +/** + * Write some bytes to the given data buffer, this function is used in Little Endian cpus. + * @param p_buffer pointer the data buffer to write data to. + * @param p_value the value to write + */ +void opj_write_float_LE(OPJ_BYTE * p_buffer, OPJ_FLOAT32 p_value); + +/*** + * Write some bytes to the given data buffer, this function is used in Big Endian cpus. + * @param p_buffer pointer the data buffer to write data to. + * @param p_value the value to write + */ +void opj_write_float_BE(OPJ_BYTE * p_buffer, OPJ_FLOAT32 p_value); + +/** + * Reads some bytes from the stream. + * @param p_stream the stream to read data from. + * @param p_buffer pointer to the data buffer that will receive the data. + * @param p_size number of bytes to read. + * @param p_event_mgr the user event manager to be notified of special events. + * @return the number of bytes read, or -1 if an error occured or if the stream is at the end. + */ +OPJ_UINT32 opj_stream_read_data (opj_stream_private_t * p_stream,OPJ_BYTE * p_buffer, OPJ_UINT32 p_size, struct opj_event_mgr * p_event_mgr); + +/** + * Writes some bytes to the stream. + * @param p_stream the stream to write data to. + * @param p_buffer pointer to the data buffer holds the data to be writtent. + * @param p_size number of bytes to write. + * @param p_event_mgr the user event manager to be notified of special events. + * @return the number of bytes writtent, or -1 if an error occured. + */ +OPJ_UINT32 opj_stream_write_data (opj_stream_private_t * p_stream,const OPJ_BYTE * p_buffer, OPJ_UINT32 p_size, struct opj_event_mgr * p_event_mgr); + +/** + * Writes the content of the stream buffer to the stream. + * @param p_stream the stream to write data to. + * @param p_event_mgr the user event manager to be notified of special events. + * @return true if the data could be flushed, false else. + */ +opj_bool opj_stream_flush (opj_stream_private_t * p_stream, struct opj_event_mgr * p_event_mgr); + +/** + * Skips a number of bytes from the stream. + * @param p_stream the stream to skip data from. + * @param p_size the number of bytes to skip. + * @param p_event_mgr the user event manager to be notified of special events. + * @return the number of bytes skipped, or -1 if an error occured. + */ +OPJ_SIZE_T opj_stream_skip (opj_stream_private_t * p_stream,OPJ_SIZE_T p_size, struct opj_event_mgr * p_event_mgr); + +/** + * Tells the byte offset on the stream (similar to ftell). + * + * @param p_stream the stream to get the information from. + * + * @return the current position o fthe stream. + */ +OPJ_SIZE_T opj_stream_tell (const opj_stream_private_t * p_stream); + +/** + * Skips a number of bytes from the stream. + * @param p_stream the stream to skip data from. + * @param p_size the number of bytes to skip. + * @param p_event_mgr the user event manager to be notified of special events. + * @return the number of bytes skipped, or -1 if an error occured. + */ +OPJ_SIZE_T opj_stream_write_skip (opj_stream_private_t * p_stream, OPJ_SIZE_T p_size, struct opj_event_mgr * p_event_mgr); + +/** + * Skips a number of bytes from the stream. + * @param p_stream the stream to skip data from. + * @param p_size the number of bytes to skip. + * @param p_event_mgr the user event manager to be notified of special events. + * @return the number of bytes skipped, or -1 if an error occured. + */ +OPJ_SIZE_T opj_stream_read_skip (opj_stream_private_t * p_stream, OPJ_SIZE_T p_size, struct opj_event_mgr * p_event_mgr); + +/** + * Skips a number of bytes from the stream. + * @param p_stream the stream to skip data from. + * @param p_size the number of bytes to skip. + * @param p_event_mgr the user event manager to be notified of special events. + * @return the number of bytes skipped, or -1 if an error occured. + */ +opj_bool opj_stream_read_seek (opj_stream_private_t * p_stream, OPJ_SIZE_T p_size, struct opj_event_mgr * p_event_mgr); + +/** + * Skips a number of bytes from the stream. + * @param p_stream the stream to skip data from. + * @param p_size the number of bytes to skip. + * @param p_event_mgr the user event manager to be notified of special events. + * @return the number of bytes skipped, or -1 if an error occured. + */ +opj_bool opj_stream_write_seek (opj_stream_private_t * p_stream, OPJ_SIZE_T p_size, struct opj_event_mgr * p_event_mgr); + +/** + * Seeks a number of bytes from the stream. + * @param p_stream the stream to skip data from. + * @param p_size the number of bytes to skip. + * @param p_event_mgr the user event manager to be notified of special events. + * @return true if the stream is seekable. + */ +opj_bool opj_stream_seek (opj_stream_private_t * p_stream, OPJ_SIZE_T p_size, struct opj_event_mgr * p_event_mgr); + +/** + * Tells if the given stream is seekable. + */ +opj_bool opj_stream_has_seek (const opj_stream_private_t * p_stream); + +OPJ_UINT32 opj_stream_default_read (void * p_buffer, OPJ_UINT32 p_nb_bytes, void * p_user_data); +OPJ_UINT32 opj_stream_default_write (void * p_buffer, OPJ_UINT32 p_nb_bytes, void * p_user_data); +OPJ_SIZE_T opj_stream_default_skip (OPJ_SIZE_T p_nb_bytes, void * p_user_data); +opj_bool opj_stream_default_seek (OPJ_SIZE_T p_nb_bytes, void * p_user_data); + + + #endif /* __CIO_H */ diff --git a/libopenjpeg/dwt.c b/libopenjpeg/dwt.c index e7d74e2f..69f385ea 100644 --- a/libopenjpeg/dwt.c +++ b/libopenjpeg/dwt.c @@ -118,7 +118,11 @@ static void dwt_encode_stepsize(int stepsize, int numbps, opj_stepsize_t *bandno /** Inverse wavelet transform in 2-D. */ +#ifdef OPJ_V1 static void dwt_decode_tile(opj_tcd_tilecomp_t* tilec, int i, DWT1DFN fn); +#endif +static opj_bool dwt_decode_tile(opj_tcd_tilecomp_t* tilec, OPJ_UINT32 i, DWT1DFN fn); + /*@}*/ @@ -375,13 +379,21 @@ void dwt_encode(opj_tcd_tilecomp_t * tilec) { } } - +#ifdef OPJ_V1 /* */ /* Inverse 5-3 wavelet transform in 2-D. */ /* */ void dwt_decode(opj_tcd_tilecomp_t* tilec, int numres) { dwt_decode_tile(tilec, numres, &dwt_decode_1); } +#endif + +/* */ +/* Inverse 5-3 wavelet transform in 2-D. */ +/* */ +opj_bool dwt_decode(opj_tcd_tilecomp_t* tilec, OPJ_UINT32 numres) { + return dwt_decode_tile(tilec, numres, &dwt_decode_1); +} /* */ @@ -495,7 +507,7 @@ void dwt_calc_explicit_stepsizes(opj_tccp_t * tccp, int prec) { } } - +#ifdef OPJ_V1 /* */ /* Determine maximum computed resolution level for inverse wavelet transform */ /* */ @@ -511,8 +523,24 @@ static int dwt_decode_max_resolution(opj_tcd_resolution_t* restrict r, int i) { } return mr ; } +#endif +/* */ +/* Determine maximum computed resolution level for inverse wavelet transform */ +/* */ +static OPJ_UINT32 dwt_max_resolution(opj_tcd_resolution_t* restrict r, OPJ_UINT32 i) { + OPJ_UINT32 mr = 0; + OPJ_UINT32 w; + while( --i ) { + ++r; + if( mr < ( w = r->x1 - r->x0 ) ) + mr = w ; + if( mr < ( w = r->y1 - r->y0 ) ) + mr = w ; + } + return mr ; +} - +#ifdef OPJ_V1 /* */ /* Inverse wavelet transform in 2-D. */ /* */ @@ -527,7 +555,7 @@ static void dwt_decode_tile(opj_tcd_tilecomp_t* tilec, int numres, DWT1DFN dwt_1 int w = tilec->x1 - tilec->x0; - h.mem = (int*)opj_aligned_malloc(dwt_decode_max_resolution(tr, numres) * sizeof(int)); + h.mem = (int*)opj_aligned_malloc(dwt_max_resolution(tr, numres) * sizeof(int)); v.mem = h.mem; while( --numres) { @@ -564,6 +592,67 @@ static void dwt_decode_tile(opj_tcd_tilecomp_t* tilec, int numres, DWT1DFN dwt_1 } opj_aligned_free(h.mem); } +#endif + +/* */ +/* Inverse wavelet transform in 2-D. */ +/* */ +static opj_bool dwt_decode_tile(opj_tcd_tilecomp_t* tilec, OPJ_UINT32 numres, DWT1DFN dwt_1D) { + dwt_t h; + dwt_t v; + + opj_tcd_resolution_t* tr = tilec->resolutions; + + OPJ_UINT32 rw = tr->x1 - tr->x0; /* width of the resolution level computed */ + OPJ_UINT32 rh = tr->y1 - tr->y0; /* height of the resolution level computed */ + + OPJ_UINT32 w = tilec->x1 - tilec->x0; + + h.mem = (OPJ_INT32*) + opj_aligned_malloc(dwt_max_resolution(tr, numres) * sizeof(OPJ_INT32)); + if + (! h.mem) + { + return OPJ_FALSE; + } + + v.mem = h.mem; + + while( --numres) { + OPJ_INT32 * restrict tiledp = tilec->data; + OPJ_UINT32 j; + + ++tr; + h.sn = rw; + v.sn = rh; + + rw = tr->x1 - tr->x0; + rh = tr->y1 - tr->y0; + + h.dn = rw - h.sn; + h.cas = tr->x0 % 2; + + for(j = 0; j < rh; ++j) { + dwt_interleave_h(&h, &tiledp[j*w]); + (dwt_1D)(&h); + memcpy(&tiledp[j*w], h.mem, rw * sizeof(OPJ_INT32)); + } + + v.dn = rh - v.sn; + v.cas = tr->y0 % 2; + + for(j = 0; j < rw; ++j){ + OPJ_UINT32 k; + dwt_interleave_v(&v, &tiledp[j], w); + (dwt_1D)(&v); + for(k = 0; k < rh; ++k) { + tiledp[k * w + j] = v.mem[k]; + } + } + } + opj_aligned_free(h.mem); + return OPJ_TRUE; +} static void v4dwt_interleave_h(v4dwt_t* restrict w, float* restrict a, int x, int size){ float* restrict bi = (float*) (w->wavelet + w->cas); @@ -769,10 +858,13 @@ static void v4dwt_decode(v4dwt_t* restrict dwt){ #endif } + +// KEEP TRUNK VERSION + return type of v2 because rev557 /* */ /* Inverse 9-7 wavelet transform in 2-D. */ /* */ -void dwt_decode_real(opj_tcd_tilecomp_t* restrict tilec, int numres){ +// V1 void dwt_decode_real(opj_tcd_tilecomp_t* restrict tilec, int numres){ +opj_bool dwt_decode_real(opj_tcd_tilecomp_t* restrict tilec, int numres){ v4dwt_t h; v4dwt_t v; @@ -783,7 +875,7 @@ void dwt_decode_real(opj_tcd_tilecomp_t* restrict tilec, int numres){ int w = tilec->x1 - tilec->x0; - h.wavelet = (v4*) opj_aligned_malloc((dwt_decode_max_resolution(res, numres)+5) * sizeof(v4)); + h.wavelet = (v4*) opj_aligned_malloc((dwt_max_resolution(res, numres)+5) * sizeof(v4)); v.wavelet = h.wavelet; while( --numres) { @@ -854,5 +946,6 @@ void dwt_decode_real(opj_tcd_tilecomp_t* restrict tilec, int numres){ } opj_aligned_free(h.wavelet); + return OPJ_TRUE; } diff --git a/libopenjpeg/dwt.h b/libopenjpeg/dwt.h index adf73e54..303fac1c 100644 --- a/libopenjpeg/dwt.h +++ b/libopenjpeg/dwt.h @@ -59,7 +59,12 @@ Apply a reversible inverse DWT transform to a component of an image. @param tilec Tile component information (current tile) @param numres Number of resolution levels to decode */ +#ifdef OPJ_V1 void dwt_decode(opj_tcd_tilecomp_t* tilec, int numres); +#endif +opj_bool dwt_decode(opj_tcd_tilecomp_t* tilec, OPJ_UINT32 numres); + + /** Get the gain of a subband for the reversible 5-3 DWT. @param orient Number that identifies the subband (0->LL, 1->HL, 2->LH, 3->HH) @@ -80,12 +85,14 @@ Apply an irreversible DWT transform to a component of an image. */ void dwt_encode_real(opj_tcd_tilecomp_t * tilec); /** +KEEP TRUNK VERSION + return type of v2 because rev557 Inverse 9-7 wavelet transform in 2-D. Apply an irreversible inverse DWT transform to a component of an image. @param tilec Tile component information (current tile) @param numres Number of resolution levels to decode */ -void dwt_decode_real(opj_tcd_tilecomp_t* tilec, int numres); +// V1 void dwt_decode_real(opj_tcd_tilecomp_t* tilec, int numres); +opj_bool dwt_decode_real(opj_tcd_tilecomp_t* tilec, int numres); /** Get the gain of a subband for the irreversible 9-7 DWT. @param orient Number that identifies the subband (0->LL, 1->HL, 2->LH, 3->HH) diff --git a/libopenjpeg/event.c b/libopenjpeg/event.c index 0dc22f12..77cec893 100644 --- a/libopenjpeg/event.c +++ b/libopenjpeg/event.c @@ -120,3 +120,48 @@ opj_bool opj_event_msg(opj_common_ptr cinfo, int event_type, const char *fmt, .. return OPJ_TRUE; } +opj_bool opj_event_msg_v2(opj_event_mgr_t* event_mgr, int event_type, const char *fmt, ...) { +#define MSG_SIZE 512 /* 512 bytes should be more than enough for a short message */ + opj_msg_callback msg_handler = NULL; + + if(event_mgr != NULL) { + switch(event_type) { + case EVT_ERROR: + msg_handler = event_mgr->error_handler; + break; + case EVT_WARNING: + msg_handler = event_mgr->warning_handler; + break; + case EVT_INFO: + msg_handler = event_mgr->info_handler; + break; + default: + break; + } + if(msg_handler == NULL) { + return OPJ_FALSE; + } + } else { + return OPJ_FALSE; + } + + if ((fmt != NULL) && (event_mgr != NULL)) { + va_list arg; + int str_length/*, i, j*/; /* UniPG */ + char message[MSG_SIZE]; + memset(message, 0, MSG_SIZE); + /* initialize the optional parameter list */ + va_start(arg, fmt); + /* check the length of the format string */ + str_length = (strlen(fmt) > MSG_SIZE) ? MSG_SIZE : strlen(fmt); + /* parse the format string and put the result in 'message' */ + vsprintf(message, fmt, arg); /* UniPG */ + /* deinitialize the optional parameter list */ + va_end(arg); + + /* output the message to the user program */ + msg_handler(message, event_mgr->client_data); + } + + return OPJ_TRUE; +} diff --git a/libopenjpeg/event.h b/libopenjpeg/event.h index 9c59787c..c8cb85e4 100644 --- a/libopenjpeg/event.h +++ b/libopenjpeg/event.h @@ -46,10 +46,13 @@ The functions in EVENT.C have for goal to send output messages (errors, warnings Write formatted data to a string and send the string to a user callback. @param cinfo Codec context info @param event_type Event type or callback to use to send the message -@param fmt Format-control string (plus optionnal arguments) +@param fmt Format-control string (plus optional arguments) @return Returns true if successful, returns false otherwise */ opj_bool opj_event_msg(opj_common_ptr cinfo, int event_type, const char *fmt, ...); + + +opj_bool opj_event_msg_v2(opj_event_mgr_t* event_mgr, int event_type, const char *fmt, ...); /* ----------------------------------------------------------------------- */ /*@}*/ diff --git a/libopenjpeg/image.c b/libopenjpeg/image.c index a4d2c010..7ca25b1e 100644 --- a/libopenjpeg/image.c +++ b/libopenjpeg/image.c @@ -87,3 +87,37 @@ void OPJ_CALLCONV opj_image_destroy(opj_image_t *image) { } } +/** + * Updates the components of the image from the coding parameters. + * + * @param p_image the image to update. + * @param p_cp the coding parameters from which to update the image. + */ +void opj_image_comp_update(opj_image_t * p_image,const opj_cp_v2_t * p_cp) +{ + OPJ_UINT32 i, l_width, l_height; + OPJ_INT32 l_x0,l_y0,l_x1,l_y1; + OPJ_INT32 l_comp_x0,l_comp_y0,l_comp_x1,l_comp_y1; + opj_image_comp_t * l_img_comp = 00; + + l_x0 = int_max(p_cp->tx0 , p_image->x0); + l_y0 = int_max(p_cp->ty0 , p_image->y0); + l_x1 = int_min(p_cp->tx0 + p_cp->tw * p_cp->tdx, p_image->x1); + l_y1 = int_min(p_cp->ty0 + p_cp->th * p_cp->tdy, p_image->y1); + + l_img_comp = p_image->comps; + for (i = 0; i < p_image->numcomps; ++i) { + l_comp_x0 = int_ceildiv(l_x0, l_img_comp->dx); + l_comp_y0 = int_ceildiv(l_y0, l_img_comp->dy); + l_comp_x1 = int_ceildiv(l_x1, l_img_comp->dx); + l_comp_y1 = int_ceildiv(l_y1, l_img_comp->dy); + l_width = int_ceildivpow2(l_comp_x1 - l_comp_x0, l_img_comp->factor); + l_height = int_ceildivpow2(l_comp_y1 - l_comp_y0, l_img_comp->factor); + l_img_comp->w = l_width; + l_img_comp->h = l_height; + l_img_comp->x0 = l_x0; + l_img_comp->y0 = l_y0; + ++l_img_comp; + } +} + diff --git a/libopenjpeg/image.h b/libopenjpeg/image.h index f828b5b7..cb6ad650 100644 --- a/libopenjpeg/image.h +++ b/libopenjpeg/image.h @@ -32,6 +32,9 @@ The functions in IMAGE.C have for goal to realize operations on images. */ +struct opj_image; +struct opj_cp_v2; + /** @defgroup IMAGE IMAGE - Implementation of operations on images */ /*@{*/ @@ -42,6 +45,14 @@ Create an empty image */ opj_image_t* opj_image_create0(void); +/** + * Updates the components of the image from the coding parameters. + * + * @param p_image the image to update. + * @param p_cp the coding parameters from which to update the image. + */ +void opj_image_comp_update(struct opj_image * p_image,const struct opj_cp_v2 * p_cp); + /*@}*/ #endif /* __IMAGE_H */ diff --git a/libopenjpeg/int.h b/libopenjpeg/int.h index 4e5fe08e..a39772b0 100644 --- a/libopenjpeg/int.h +++ b/libopenjpeg/int.h @@ -50,6 +50,15 @@ Get the minimum of two integers static INLINE int int_min(int a, int b) { return a < b ? a : b; } + +/** +Get the minimum of two integers +@return Returns a if a < b else b +*/ +static INLINE OPJ_UINT32 uint_min(OPJ_UINT32 a, OPJ_UINT32 b) { + return a < b ? a : b; +} + /** Get the maximum of two integers @return Returns a if a > b else b @@ -57,6 +66,15 @@ Get the maximum of two integers static INLINE int int_max(int a, int b) { return (a > b) ? a : b; } + +/** +Get the maximum of two integers +@return Returns a if a > b else b +*/ +static INLINE OPJ_UINT32 uint_max(OPJ_UINT32 a, OPJ_UINT32 b) { + return (a > b) ? a : b; +} + /** Clamp an integer inside an interval @return @@ -111,6 +129,19 @@ static INLINE int int_floorlog2(int a) { } return l; } +/** +Get logarithm of an integer and round downwards +@return Returns log2(a) +*/ +static INLINE OPJ_UINT32 uint_floorlog2(OPJ_UINT32 a) { + OPJ_UINT32 l; + for (l = 0; a > 1; ++l) + { + a >>= 1; + } + return l; +} + /* ----------------------------------------------------------------------- */ /*@}*/ diff --git a/libopenjpeg/j2k.c b/libopenjpeg/j2k.c index af8061a2..2732014e 100644 --- a/libopenjpeg/j2k.c +++ b/libopenjpeg/j2k.c @@ -39,6 +39,158 @@ /** @name Local static functions */ /*@{*/ +/** + * 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); + +/** + * 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); + +/** + * 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 + ); + +/** + * 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_decoding_validation (opj_j2k_v2_t *p_j2k); + +/** + * 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 + ); + +/** + * 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. + */ +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 + ); + +/** + * 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 + ); + +/** + * 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. +*/ +static const struct opj_dec_memory_marker_handler * j2k_get_marker_handler (OPJ_UINT32 p_id); + +/** + * Destroys a tile coding parameter structure. + * + * @param p_tcp the tile coding parameter to destroy. + */ +static void j2k_tcp_destroy (opj_tcp_v2_t *p_tcp); + +/** + * Destroys a coding parameter structure. + * + * @param p_cp the coding parameter to destroy. + */ +static void j2k_cp_destroy (opj_cp_v2_t *p_cp); + + +/** + * 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. +*/ +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 + ); + +/** + * Reads 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_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 + ); + +/** + * 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 + ); + +/** + * 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 + ); + +/* + * ----------------------------------------------------------------------- + * ----------------------------------------------------------------------- + * ----------------------------------------------------------------------- + */ + /** Write the SOC marker (Start Of Codestream) @param j2k J2K handle @@ -49,6 +201,20 @@ Read the SOC marker (Start of Codestream) @param j2k J2K handle */ static void j2k_read_soc(opj_j2k_t *j2k); + +/** + * Reads a SOC marker (Start of Codestream) + * @param p_header_data the data contained in the SOC box. + * @param jp2 the jpeg2000 file codec. + * @param p_header_size the size of the data contained in the SOC marker. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_read_soc_v2( + opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); + /** Write the SIZ marker (image and tile size) @param j2k J2K handle @@ -59,6 +225,21 @@ Read the SIZ marker (image and tile size) @param j2k J2K handle */ static void j2k_read_siz(opj_j2k_t *j2k); + +/** + * Reads a SIZ marker (image and tile size) + * @param p_header_data the data contained in the SIZ box. + * @param jp2 the jpeg2000 file codec. + * @param p_header_size the size of the data contained in the SIZ marker. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_read_siz_v2 ( + opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); + /** Write the COM marker (comment) @param j2k J2K handle @@ -69,6 +250,19 @@ Read the COM marker (comment) @param j2k J2K handle */ static void j2k_read_com(opj_j2k_t *j2k); +/** + * Reads a COM marker (comments) + * @param p_header_data the data contained in the COM box. + * @param jp2 the jpeg2000 file codec. + * @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_com_v2 ( + opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); /** Write the value concerning the specified component in the marker COD and COC @param j2k J2K handle @@ -91,6 +285,21 @@ Read the COD marker (coding style default) @param j2k J2K handle */ static void j2k_read_cod(opj_j2k_t *j2k); + +/** + * Reads a COD marker (Coding Styke defaults) + * @param p_header_data the data contained in the COD box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the COD marker. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_read_cod_v2 ( + opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); + /** Write the COC marker (coding style component) @param j2k J2K handle @@ -102,6 +311,21 @@ Read the COC marker (coding style component) @param j2k J2K handle */ static void j2k_read_coc(opj_j2k_t *j2k); + +/** + * Reads a COC marker (Coding Style Component) + * @param p_header_data the data contained in the COC box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the COC marker. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_read_coc_v2 ( + opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); + /** Write the value concerning the specified component in the marker QCD and QCC @param j2k J2K handle @@ -125,6 +349,21 @@ Read the QCD marker (quantization default) @param j2k J2K handle */ static void j2k_read_qcd(opj_j2k_t *j2k); + +/** + * 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. +*/ +static 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 + ); + /** Write the QCC marker (quantization component) @param j2k J2K handle @@ -136,6 +375,19 @@ Read the QCC marker (quantization component) @param j2k J2K handle */ static void j2k_read_qcc(opj_j2k_t *j2k); +/** + * Reads a QCC marker (Quantization component) + * @param p_header_data the data contained in the QCC box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the QCC marker. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_read_qcc_v2( + opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager); + /** Write the POC marker (progression order change) @param j2k J2K handle @@ -146,36 +398,135 @@ Read the POC marker (progression order change) @param j2k J2K handle */ static void j2k_read_poc(opj_j2k_t *j2k); +/** + * Reads a POC marker (Progression Order Change) + * + * @param p_header_data the data contained in the POC box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the POC marker. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_read_poc_v2 ( + opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); /** Read the CRG marker (component registration) @param j2k J2K handle */ static void j2k_read_crg(opj_j2k_t *j2k); +/** + * Reads a CRG marker (Component registration) + * + * @param p_header_data the data contained in the TLM box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the TLM marker. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_read_crg_v2 ( + opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); /** Read the TLM marker (tile-part lengths) @param j2k J2K handle */ static void j2k_read_tlm(opj_j2k_t *j2k); +/** + * Reads a TLM marker (Tile Length Marker) + * + * @param p_header_data the data contained in the TLM box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the TLM marker. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_read_tlm_v2 ( + opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); /** Read the PLM marker (packet length, main header) @param j2k J2K handle */ static void j2k_read_plm(opj_j2k_t *j2k); + +/** + * Reads a PLM marker (Packet length, main header marker) + * + * @param p_header_data the data contained in the TLM box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the TLM marker. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_read_plm_v2 ( + opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); /** Read the PLT marker (packet length, tile-part header) @param j2k J2K handle */ static void j2k_read_plt(opj_j2k_t *j2k); +/** + * Reads a PLT marker (Packet length, tile-part header) + * + * @param p_header_data the data contained in the PLT box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the PLT marker. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_read_plt_v2 ( + opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); /** Read the PPM marker (packet packet headers, main header) @param j2k J2K handle */ static void j2k_read_ppm(opj_j2k_t *j2k); +/** + * Reads a PPM marker (Packed packet headers, main header) + * + * @param p_header_data the data contained in the POC box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the POC marker. + * @param p_manager the user event manager. +*/ +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 + ); /** Read the PPT marker (packet packet headers, tile-part header) @param j2k J2K handle */ static void j2k_read_ppt(opj_j2k_t *j2k); +/** + * Reads a PPT marker (Packed packet headers, tile-part header) + * + * @param p_header_data the data contained in the PPT box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the PPT marker. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_read_ppt_v2 ( + opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); /** Write the TLM marker (Mainheader) @param j2k J2K handle @@ -191,6 +542,21 @@ Read the SOT marker (start of tile-part) @param j2k J2K handle */ static void j2k_read_sot(opj_j2k_t *j2k); + +/** + * Reads a PPT marker (Packed packet headers, tile-part header) + * + * @param p_header_data the data contained in the PPT box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the PPT marker. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_read_sot_v2 ( + opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); /** Write the SOD marker (start of data) @param j2k J2K handle @@ -214,6 +580,22 @@ Read the RGN marker (region-of-interest) @param j2k J2K handle */ static void j2k_read_rgn(opj_j2k_t *j2k); + +/** + * Reads a RGN marker (Region Of Interest) + * + * @param p_header_data the data contained in the POC box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the POC marker. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_read_rgn_v2 ( + opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ) ; + /** Write the EOC marker (end of codestream) @param j2k J2K handle @@ -266,6 +648,82 @@ j2k_prog_order_t j2k_prog_order_list[] = { {(OPJ_PROG_ORDER)-1, ""} }; +typedef struct opj_dec_memory_marker_handler +{ + /** marker value */ + OPJ_UINT32 id; + /** value of the state when the marker can appear */ + OPJ_UINT32 states; + /** action linked to the marker */ + opj_bool (*handler) ( + opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); +} +opj_dec_memory_marker_handler_t; + +const opj_dec_memory_marker_handler_t j2k_memory_marker_handler_tab [] = +{ +#ifdef TODO_MS + {J2K_MS_SOT, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPHSOT, j2k_read_sot}, + {J2K_MS_COD, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPH, j2k_read_cod}, + {J2K_MS_COC, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPH, j2k_read_coc}, + {J2K_MS_RGN, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPH, j2k_read_rgn}, + {J2K_MS_QCD, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPH, j2k_read_qcd}, + {J2K_MS_QCC, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPH, j2k_read_qcc}, + {J2K_MS_POC, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPH, j2k_read_poc}, + {J2K_MS_SIZ, J2K_DEC_STATE_MHSIZ , j2k_read_siz}, + {J2K_MS_TLM, J2K_DEC_STATE_MH, j2k_read_tlm}, + {J2K_MS_PLM, J2K_DEC_STATE_MH, j2k_read_plm}, + {J2K_MS_PLT, J2K_DEC_STATE_TPH, j2k_read_plt}, + {J2K_MS_PPM, J2K_DEC_STATE_MH, j2k_read_ppm}, + {J2K_MS_PPT, J2K_DEC_STATE_TPH, j2k_read_ppt}, + {J2K_MS_SOP, 0, 0}, + {J2K_MS_CRG, J2K_DEC_STATE_MH, j2k_read_crg}, + {J2K_MS_COM, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPH, j2k_read_com}, + {J2K_MS_MCT, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPH, j2k_read_mct}, + {J2K_MS_CBD, J2K_DEC_STATE_MH , j2k_read_cbd}, + {J2K_MS_MCC, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPH, j2k_read_mcc}, + {J2K_MS_MCO, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPH, j2k_read_mco}, +#endif + {J2K_MS_SOT, J2K_STATE_MH | J2K_STATE_TPHSOT, j2k_read_sot_v2}, + {J2K_MS_COD, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_cod_v2}, + {J2K_MS_COC, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_coc_v2}, + {J2K_MS_RGN, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_rgn_v2}, + {J2K_MS_QCD, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_qcd_v2}, + {J2K_MS_QCC, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_qcc_v2}, + {J2K_MS_POC, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_poc_v2}, + {J2K_MS_SIZ, J2K_STATE_MHSIZ , j2k_read_siz_v2}, + {J2K_MS_TLM, J2K_STATE_MH, j2k_read_tlm_v2}, + {J2K_MS_PLM, J2K_STATE_MH, j2k_read_plm_v2}, + {J2K_MS_PLT, J2K_STATE_TPH, j2k_read_plt_v2}, + {J2K_MS_PPM, J2K_STATE_MH, j2k_read_ppm_v2}, + {J2K_MS_PPT, J2K_STATE_TPH, j2k_read_ppt_v2}, + {J2K_MS_SOP, 0, 0}, + {J2K_MS_CRG, J2K_STATE_MH, j2k_read_crg_v2}, + {J2K_MS_COM, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_com_v2}, +#ifdef TODO_MS + {J2K_MS_MCT, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_mct}, + {J2K_MS_CBD, J2K_STATE_MH , j2k_read_cbd}, + {J2K_MS_MCC, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_mcc}, + {J2K_MS_MCO, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_mco}, +#endif +#ifdef USE_JPWL + {J2K_MS_EPC, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPH, j2k_read_epc}, + {J2K_MS_EPB, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPH, j2k_read_epb}, + {J2K_MS_ESD, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPH, j2k_read_esd}, + {J2K_MS_RED, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPH, j2k_read_red}, +#endif /* USE_JPWL */ +#ifdef USE_JPSEC + {J2K_MS_SEC, J2K_DEC_STATE_MH, j2k_read_sec}, + {J2K_MS_INSEC, 0, j2k_read_insec} +#endif /* USE_JPSEC */ +}; + + + char *j2k_convert_progression_order(OPJ_PROG_ORDER prg_order){ j2k_prog_order_t *po; for(po = j2k_prog_order_list; po->enum_prog != -1; po++ ){ @@ -367,6 +825,48 @@ static void j2k_read_soc(opj_j2k_t *j2k) { } } +/** + * Reads a SOC marker (Start of Codestream) + * @param p_header_data the data contained in the SOC box. + * @param jp2 the jpeg2000 file codec. + * @param p_header_size the size of the data contained in the SOC marker. + * @param p_manager the user event manager. +*/ +opj_bool j2k_read_soc_v2( + opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_BYTE l_data [2]; + OPJ_UINT32 l_marker; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + if (opj_stream_read_data(p_stream,l_data,2,p_manager) != 2) { + return OPJ_FALSE; + } + + opj_read_bytes(l_data,&l_marker,2); + if (l_marker != J2K_MS_SOC) { + return OPJ_FALSE; + } + + /* assure length of data is correct (0) */ + p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_MHSIZ; // FIXME J2K_DEC_STATE_MHSIZ; + + /* Index */ + if (p_j2k->cstr_info) { + //TODO p_j2k->cstr_info->main_head_start = opj_stream_tell(p_stream) - 2; // why - 2 ? + p_j2k->cstr_info->codestream_size = 0;/*p_stream_numbytesleft(p_j2k->p_stream) + 2 - p_j2k->cstr_info->main_head_start*/; + } + + return OPJ_TRUE; +} + static void j2k_write_siz(opj_j2k_t *j2k) { int i; int lenp, len; @@ -611,6 +1111,340 @@ static void j2k_read_siz(opj_j2k_t *j2k) { } } + +/** + * Reads a SIZ marker (image and tile size) + * @param p_header_data the data contained in the SIZ box. + * @param jp2 the jpeg2000 file codec. + * @param p_header_size the size of the data contained in the SIZ marker. + * @param p_manager the user event manager. +*/ +opj_bool j2k_read_siz_v2 ( + 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_size, i; + OPJ_UINT32 l_nb_comp; + OPJ_UINT32 l_nb_comp_remain; + OPJ_UINT32 l_remaining_size; + OPJ_UINT32 l_nb_tiles; + OPJ_UINT32 l_tmp; + opj_image_t *l_image = 00; + opj_cp_v2_t *l_cp = 00; + opj_image_comp_t * l_img_comp = 00; + opj_tcp_v2_t * l_current_tile_param = 00; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_header_data != 00); + + l_image = p_j2k->m_image; + l_cp = &(p_j2k->m_cp); + + // 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; + } + + l_remaining_size = p_header_size - 36; + l_nb_comp = l_remaining_size / 3; + l_nb_comp_remain = l_remaining_size % 3; + if (l_nb_comp_remain != 0){ + opj_event_msg_v2(p_manager, EVT_ERROR, "Error with SIZ marker size\n"); + return OPJ_FALSE; + } + + l_size = p_header_size + 2; /* Lsiz */ + + opj_read_bytes(p_header_data,&l_tmp ,2); /* Rsiz (capabilities) */ + p_header_data+=2; + l_cp->rsiz = (OPJ_RSIZ_CAPABILITIES) l_tmp; + opj_read_bytes(p_header_data, (OPJ_UINT32*) &l_image->x1, 4); /* Xsiz */ + p_header_data+=4; + opj_read_bytes(p_header_data, (OPJ_UINT32*) &l_image->y1, 4); /* Ysiz */ + p_header_data+=4; + opj_read_bytes(p_header_data, (OPJ_UINT32*) &l_image->x0, 4); /* X0siz */ + p_header_data+=4; + opj_read_bytes(p_header_data, (OPJ_UINT32*) &l_image->y0, 4); /* Y0siz */ + p_header_data+=4; + opj_read_bytes(p_header_data, (OPJ_UINT32*) &l_cp->tdx, 4); /* XTsiz */ + p_header_data+=4; + opj_read_bytes(p_header_data, (OPJ_UINT32*) &l_cp->tdy, 4); /* YTsiz */ + p_header_data+=4; + opj_read_bytes(p_header_data, (OPJ_UINT32*) &l_cp->tx0, 4); /* XT0siz */ + p_header_data+=4; + opj_read_bytes(p_header_data, (OPJ_UINT32*) &l_cp->ty0, 4); /* YT0siz */ + p_header_data+=4; + opj_read_bytes(p_header_data, (OPJ_UINT32*) &l_tmp, 2); /* Csiz */ + p_header_data+=2; + if (l_tmp < 16385) + l_image->numcomps = (OPJ_UINT16) l_tmp; + else { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error with SIZ marker: number of component is illegal -> %d\n", l_tmp); + return OPJ_FALSE; + } + + if (l_image->numcomps != l_nb_comp) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error with SIZ marker: number of component is not compatible with the remaining number of parameters ( %d vs %d)\n", l_image->numcomps, l_nb_comp); + return OPJ_FALSE; + } + +#ifdef USE_JPWL + if (p_j2k->m_cp->correct) { + /* if JPWL is on, we check whether TX errors have damaged + too much the SIZ parameters */ + if (!(image->x1 * image->y1)) { + opj_event_msg(p_j2k->cinfo, EVT_ERROR, + "JPWL: bad image size (%d x %d)\n", + image->x1, image->y1); + if (!JPWL_ASSUME || JPWL_ASSUME) { + opj_event_msg(p_j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + } + if (image->numcomps != ((len - 38) / 3)) { + opj_event_msg(p_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)); + if (!JPWL_ASSUME) { + opj_event_msg(p_j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + /* we try to correct */ + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- trying to adjust this\n"); + if (image->numcomps < ((len - 38) / 3)) { + len = 38 + 3 * image->numcomps; + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- setting Lsiz to %d => HYPOTHESIS!!!\n", + len); + } else { + image->numcomps = ((len - 38) / 3); + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- setting Csiz to %d => HYPOTHESIS!!!\n", + image->numcomps); + } + } + + /* update components number in the jpwl_exp_comps filed */ + cp->exp_comps = image->numcomps; + } +#endif /* USE_JPWL */ + + // 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; + opj_event_msg_v2(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n"); + return OPJ_FALSE; + } + + memset(l_image->comps,0,l_image->numcomps * sizeof(opj_image_comp_t)); + l_img_comp = l_image->comps; + + // 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 */ + ++p_header_data; + l_img_comp->prec = (tmp & 0x7f) + 1; + 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 + 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 + +#ifdef USE_JPWL + if (p_j2k->m_cp->correct) { + /* if JPWL is on, we check whether TX errors have damaged + too much the SIZ parameters, again */ + if (!(image->comps[i].dx * image->comps[i].dy)) { + opj_event_msg(p_j2k->cinfo, JPWL_ASSUME ? EVT_WARNING : EVT_ERROR, + "JPWL: bad XRsiz_%d/YRsiz_%d (%d x %d)\n", + i, i, image->comps[i].dx, image->comps[i].dy); + if (!JPWL_ASSUME) { + opj_event_msg(p_j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + /* we try to correct */ + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- trying to adjust them\n"); + if (!image->comps[i].dx) { + image->comps[i].dx = 1; + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- setting XRsiz_%d to %d => HYPOTHESIS!!!\n", + i, image->comps[i].dx); + } + if (!image->comps[i].dy) { + image->comps[i].dy = 1; + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- setting YRsiz_%d to %d => HYPOTHESIS!!!\n", + i, image->comps[i].dy); + } + } + } +#endif /* USE_JPWL */ + l_img_comp->resno_decoded = 0; /* number of resolution decoded */ + l_img_comp->factor = l_cp->m_specific_param.m_dec.m_reduce; /* reducing factor per component */ + ++l_img_comp; + } + + // 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 + 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; + p_j2k->m_specific_param.m_decoder.m_end_tile_x = int_ceildiv((p_j2k->m_specific_param.m_decoder.m_end_tile_x - l_cp->tx0), l_cp->tdx); + p_j2k->m_specific_param.m_decoder.m_end_tile_y = int_ceildiv((p_j2k->m_specific_param.m_decoder.m_end_tile_y - l_cp->ty0), l_cp->tdy); + } + else { + 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; + } + +#ifdef USE_JPWL + if (p_j2k->m_cp->correct) { + /* if JPWL is on, we check whether TX errors have damaged + too much the SIZ parameters */ + if ((cp->tw < 1) || (cp->th < 1) || (cp->tw > cp->max_tiles) || (cp->th > cp->max_tiles)) { + opj_event_msg(p_j2k->cinfo, JPWL_ASSUME ? EVT_WARNING : EVT_ERROR, + "JPWL: bad number of tiles (%d x %d)\n", + cp->tw, cp->th); + if (!JPWL_ASSUME) { + opj_event_msg(p_j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + /* we try to correct */ + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- trying to adjust them\n"); + if (cp->tw < 1) { + cp->tw= 1; + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- setting %d tiles in x => HYPOTHESIS!!!\n", + cp->tw); + } + if (cp->tw > cp->max_tiles) { + cp->tw= 1; + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- too large x, increase expectance of %d\n" + "- setting %d tiles in x => HYPOTHESIS!!!\n", + cp->max_tiles, cp->tw); + } + if (cp->th < 1) { + cp->th= 1; + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- setting %d tiles in y => HYPOTHESIS!!!\n", + cp->th); + } + if (cp->th > cp->max_tiles) { + cp->th= 1; + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- too large y, increase expectance of %d to continue\n", + "- setting %d tiles in y => HYPOTHESIS!!!\n", + cp->max_tiles, cp->th); + } + } + } +#endif /* USE_JPWL */ + + /* memory allocations */ + l_cp->tcps = (opj_tcp_v2_t*) opj_calloc(l_nb_tiles, sizeof(opj_tcp_v2_t)); + if (l_cp->tcps == 00) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n"); + return OPJ_FALSE; + } + memset(l_cp->tcps,0,l_nb_tiles*sizeof(opj_tcp_t)); + +#ifdef USE_JPWL + if (p_j2k->m_cp->correct) { + if (!cp->tcps) { + opj_event_msg(p_j2k->cinfo, JPWL_ASSUME ? EVT_WARNING : EVT_ERROR, + "JPWL: could not alloc tcps field of cp\n"); + if (!JPWL_ASSUME || JPWL_ASSUME) { + opj_event_msg(p_j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + } + } +#endif /* USE_JPWL */ + + p_j2k->m_specific_param.m_decoder.m_default_tcp->tccps = + (opj_tccp_t*) opj_calloc(l_image->numcomps, sizeof(opj_tccp_t)); + if(p_j2k->m_specific_param.m_decoder.m_default_tcp->tccps == 00) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n"); + return OPJ_FALSE; + } + memset(p_j2k->m_specific_param.m_decoder.m_default_tcp->tccps ,0,l_image->numcomps*sizeof(opj_tccp_t)); + + p_j2k->m_specific_param.m_decoder.m_default_tcp->m_mct_records = + (opj_mct_data_t*)opj_malloc(J2K_MCT_DEFAULT_NB_RECORDS * sizeof(opj_mct_data_t)); + + if (! p_j2k->m_specific_param.m_decoder.m_default_tcp->m_mct_records) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n"); + return OPJ_FALSE; + } + memset(p_j2k->m_specific_param.m_decoder.m_default_tcp->m_mct_records,0,J2K_MCT_DEFAULT_NB_RECORDS * sizeof(opj_mct_data_t)); + p_j2k->m_specific_param.m_decoder.m_default_tcp->m_nb_max_mct_records = J2K_MCT_DEFAULT_NB_RECORDS; + + p_j2k->m_specific_param.m_decoder.m_default_tcp->m_mcc_records = + (opj_simple_mcc_decorrelation_data_t*) + opj_malloc(J2K_MCC_DEFAULT_NB_RECORDS * sizeof(opj_simple_mcc_decorrelation_data_t)); + + if (! p_j2k->m_specific_param.m_decoder.m_default_tcp->m_mcc_records) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n"); + return OPJ_FALSE; + } + memset(p_j2k->m_specific_param.m_decoder.m_default_tcp->m_mcc_records,0,J2K_MCC_DEFAULT_NB_RECORDS * sizeof(opj_simple_mcc_decorrelation_data_t)); + p_j2k->m_specific_param.m_decoder.m_default_tcp->m_nb_max_mcc_records = J2K_MCC_DEFAULT_NB_RECORDS; + + /* set up default dc level shift */ + for (i=0;inumcomps;++i) { + if (! l_image->comps[i].sgnd) { + p_j2k->m_specific_param.m_decoder.m_default_tcp->tccps[i].m_dc_level_shift = 1 << (l_image->comps[i].prec - 1); + } + } + + l_current_tile_param = l_cp->tcps; + for (i = 0; i < l_nb_tiles; ++i) { + l_current_tile_param->tccps = (opj_tccp_t*) opj_malloc(l_image->numcomps * sizeof(opj_tccp_t)); + if (l_current_tile_param->tccps == 00) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n"); + return OPJ_FALSE; + } + memset(l_current_tile_param->tccps,0,l_image->numcomps * sizeof(opj_tccp_t)); + + ++l_current_tile_param; + } + + p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_MH; // FIXME J2K_DEC_STATE_MH; + opj_image_comp_update(l_image,l_cp); + + /* Index */ + if (p_j2k->cstr_info) { + opj_codestream_info_t *cstr_info = p_j2k->cstr_info; + cstr_info->image_w = l_image->x1 - l_image->x0; + cstr_info->image_h = l_image->y1 - l_image->y0; + cstr_info->numcomps = l_image->numcomps; + cstr_info->tw = l_cp->tw; + cstr_info->th = l_cp->th; + cstr_info->tile_x = l_cp->tdx; + cstr_info->tile_y = l_cp->tdy; + cstr_info->tile_Ox = l_cp->tx0; + cstr_info->tile_Oy = l_cp->ty0; + cstr_info->tile = (opj_tile_info_t*) opj_calloc(l_nb_tiles, sizeof(opj_tile_info_t)); + if (cstr_info->tile == 00) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n"); + return OPJ_FALSE; + } + memset(cstr_info->tile,0,l_nb_tiles * sizeof(opj_tile_info_t)); + } + return OPJ_TRUE; +} + + + static void j2k_write_com(opj_j2k_t *j2k) { unsigned int i; int lenp, len; @@ -646,6 +1480,27 @@ static void j2k_read_com(opj_j2k_t *j2k) { len = cio_read(cio, 2); cio_skip(cio, len - 2); } +/** + * Reads a COM marker (comments) + * @param p_header_data the data contained in the COM box. + * @param jp2 the jpeg2000 file 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_com_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_j2k != 00); + assert(p_manager != 00); + assert(p_header_data != 00); + + return OPJ_TRUE; +} static void j2k_write_cox(opj_j2k_t *j2k, int compno) { int i; @@ -777,6 +1632,89 @@ static void j2k_read_cod(opj_j2k_t *j2k) { } } +/** + * Reads a COD marker (Coding Styke defaults) + * @param p_header_data the data contained in the COD box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the COD marker. + * @param p_manager the user event manager. +*/ +opj_bool j2k_read_cod_v2 ( + opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ) +{ + // loop + OPJ_UINT32 i; + OPJ_UINT32 l_tmp; + opj_cp_v2_t *l_cp = 00; + opj_tcp_v2_t *l_tcp = 00; + opj_image_t *l_image = 00; + + // preconditions + assert(p_header_data != 00); + assert(p_j2k != 00); + assert(p_manager != 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_image = p_j2k->m_image; + + // make sure room is sufficient + if (p_header_size < 5) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading COD marker\n"); + return OPJ_FALSE; + } + + opj_read_bytes(p_header_data,&l_tcp->csty,1); /* Scod */ + ++p_header_data; + opj_read_bytes(p_header_data,&l_tmp,1); /* SGcod (A) */ + ++p_header_data; + l_tcp->prg = (OPJ_PROG_ORDER) l_tmp; + opj_read_bytes(p_header_data,&l_tcp->numlayers,2); /* SGcod (B) */ + p_header_data+=2; + 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; + } + else { + l_tcp->num_layers_to_decode = l_tcp->numlayers; + } + + opj_read_bytes(p_header_data,&l_tcp->mct,1); /* SGcod (C) */ + ++p_header_data; + + p_header_size -= 5; + for (i = 0; i < l_image->numcomps; ++i) { + l_tcp->tccps[i].csty = l_tcp->csty & J2K_CCP_CSTY_PRT; + } + + if (! j2k_read_SPCod_SPCoc(p_j2k,0,p_header_data,&p_header_size,p_manager)) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading COD marker\n"); + return OPJ_FALSE; + } + + if (p_header_size != 0) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading COD marker\n"); + return OPJ_FALSE; + } + j2k_copy_tile_component_parameters(p_j2k); + + + /* Index */ + if (p_j2k->cstr_info) { + opj_codestream_info_t *l_cstr_info = p_j2k->cstr_info; + l_cstr_info->prog = l_tcp->prg; + l_cstr_info->numlayers = l_tcp->numlayers; + l_cstr_info->numdecompos = (OPJ_INT32*) opj_malloc(l_image->numcomps * sizeof(OPJ_UINT32)); + for (i = 0; i < l_image->numcomps; ++i) { + l_cstr_info->numdecompos[i] = l_tcp->tccps[i].numresolutions - 1; + } + } + return OPJ_TRUE; +} + static void j2k_write_coc(opj_j2k_t *j2k, int compno) { int lenp, len; @@ -811,6 +1749,65 @@ static void j2k_read_coc(opj_j2k_t *j2k) { j2k_read_cox(j2k, compno); } +/** + * Reads a COC marker (Coding Style Component) + * @param p_header_data the data contained in the COC box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the COC marker. + * @param p_manager the user event manager. +*/ +opj_bool j2k_read_coc_v2 ( + opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ) +{ + opj_cp_v2_t *l_cp = NULL; + opj_tcp_v2_t *l_tcp = NULL; + opj_image_t *l_image = NULL; + OPJ_UINT32 l_comp_room; + OPJ_UINT32 l_comp_no; + + // preconditions + assert(p_header_data != 00); + assert(p_j2k != 00); + assert(p_manager != 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_image = p_j2k->m_image; + + l_comp_room = l_image->numcomps <= 256 ? 1 : 2; + + // 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; + } + p_header_size -= l_comp_room + 1; + + opj_read_bytes(p_header_data,&l_comp_no,l_comp_room); /* Ccoc */ + p_header_data += l_comp_room; + if (l_comp_no >= l_image->numcomps) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading COC marker (bad number of components)\n"); + return OPJ_FALSE; + } + opj_read_bytes(p_header_data,&l_tcp->tccps[l_comp_no].csty,1); /* Scoc */ + ++p_header_data ; + + if (! j2k_read_SPCod_SPCoc(p_j2k,l_comp_no,p_header_data,&p_header_size,p_manager)) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading COC marker\n"); + return OPJ_FALSE; + } + + if (p_header_size != 0) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading COC marker\n"); + return OPJ_FALSE; + } + return OPJ_TRUE; +} + static void j2k_write_qcx(opj_j2k_t *j2k, int compno) { int bandno, numbands; int expn, mant; @@ -941,6 +1938,38 @@ static void j2k_read_qcd(opj_j2k_t *j2k) { } } +/** + * 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; + } + j2k_copy_tile_quantization_parameters(p_j2k); + + return OPJ_TRUE; +} + static void j2k_write_qcc(opj_j2k_t *j2k, int compno) { int lenp, len; @@ -994,6 +2023,87 @@ static void j2k_read_qcc(opj_j2k_t *j2k) { j2k_read_qcx(j2k, compno, len - 2 - (numcomp <= 256 ? 1 : 2)); } +/** + * Reads a QCC marker (Quantization component) + * @param p_header_data the data contained in the QCC box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the QCC marker. + * @param p_manager the user event manager. +*/ +opj_bool j2k_read_qcc_v2( + 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_num_comp,l_comp_no; + + // preconditions + assert(p_header_data != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + l_num_comp = p_j2k->m_image->numcomps; + +#ifdef USE_JPWL + if (p_j2k->m_cp->correct) { + + static OPJ_UINT32 backup_compno = 0; + + /* compno is negative or larger than the number of components!!! */ + if ((compno < 0) || (compno >= numcomp)) { + opj_event_msg(p_j2k->cinfo, EVT_ERROR, + "JPWL: bad component number in QCC (%d out of a maximum of %d)\n", + compno, numcomp); + if (!JPWL_ASSUME) { + opj_event_msg(p_j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + /* we try to correct */ + compno = backup_compno % numcomp; + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- trying to adjust this\n" + "- setting component number to %d\n", + compno); + } + + /* keep your private count of tiles */ + backup_compno++; + }; +#endif /* USE_JPWL */ + + if (l_num_comp <= 256) { + if (p_header_size < 1) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading QCC marker\n"); + return OPJ_FALSE; + } + opj_read_bytes(p_header_data,&l_comp_no,1); + ++p_header_data; + --p_header_size; + } + else { + if (p_header_size < 2) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading QCC marker\n"); + return OPJ_FALSE; + } + opj_read_bytes(p_header_data,&l_comp_no,2); + p_header_data+=2; + p_header_size-=2; + } + + if (! j2k_read_SQcd_SQcc(p_j2k,l_comp_no,p_header_data,&p_header_size,p_manager)) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading QCC marker\n"); + return OPJ_FALSE; + } + + if (p_header_size != 0) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading QCC marker\n"); + return OPJ_FALSE; + } + + return OPJ_TRUE; +} + + static void j2k_write_poc(opj_j2k_t *j2k) { int len, numpchgs, i; @@ -1051,6 +2161,88 @@ static void j2k_read_poc(opj_j2k_t *j2k) { tcp->numpocs = numpchgs + old_poc - 1; } +/** + * Reads a POC marker (Progression Order Change) + * + * @param p_header_data the data contained in the POC box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the POC marker. + * @param p_manager the user event manager. +*/ +opj_bool j2k_read_poc_v2 ( + 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_UINT32 l_nb_comp; + opj_image_t * l_image = 00; + OPJ_UINT32 l_old_poc_nb,l_current_poc_nb,l_current_poc_remaining; + OPJ_UINT32 l_chunk_size; + OPJ_UINT32 l_tmp; + + opj_cp_v2_t *l_cp = 00; + opj_tcp_v2_t *l_tcp = 00; + opj_poc_t *l_current_poc = 00; + OPJ_UINT32 l_comp_room; + + // preconditions + assert(p_header_data != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + l_image = p_j2k->m_image; + l_nb_comp = l_image->numcomps; + if (l_nb_comp <= 256) { + l_comp_room = 1; + } + else { + l_comp_room = 2; + } + l_chunk_size = 5 + 2 * l_comp_room; + l_current_poc_nb = p_header_size / l_chunk_size; + l_current_poc_remaining = p_header_size % l_chunk_size; + + if ((l_current_poc_nb <= 0) || (l_current_poc_remaining != 0)) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading POC marker\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; + l_old_poc_nb = l_tcp->POC ? l_tcp->numpocs + 1 : 0; + l_current_poc_nb += l_old_poc_nb; + + assert(l_current_poc_nb < 32); + + /* now poc is in use.*/ + l_tcp->POC = 1; + + l_current_poc = &l_tcp->pocs[l_old_poc_nb]; + for (i = l_old_poc_nb; i < l_current_poc_nb; ++i) { + opj_read_bytes(p_header_data,&(l_current_poc->resno0),1); /* RSpoc_i */ + ++p_header_data; + opj_read_bytes(p_header_data,&(l_current_poc->compno0),l_comp_room); /* CSpoc_i */ + p_header_data+=l_comp_room; + opj_read_bytes(p_header_data,&(l_current_poc->layno1),2); /* LYEpoc_i */ + p_header_data+=2; + opj_read_bytes(p_header_data,&(l_current_poc->resno1),1); /* REpoc_i */ + ++p_header_data; + opj_read_bytes(p_header_data,&(l_current_poc->compno1),l_comp_room); /* CEpoc_i */ + p_header_data+=l_comp_room; + opj_read_bytes(p_header_data,&l_tmp,1); /* Ppoc_i */ + ++p_header_data; + l_current_poc->prg = (OPJ_PROG_ORDER) l_tmp; + /* make sure comp is in acceptable bounds */ + l_current_poc->compno1 = uint_min(l_current_poc->compno1, l_nb_comp); + ++l_current_poc; + } + + l_tcp->numpocs = l_current_poc_nb - 1; + return OPJ_TRUE; +} + static void j2k_read_crg(opj_j2k_t *j2k) { int len, i, Xcrg_i, Ycrg_i; @@ -1064,6 +2256,47 @@ static void j2k_read_crg(opj_j2k_t *j2k) { } } +/** + * Reads a CRG marker (Component registration) + * + * @param p_header_data the data contained in the TLM box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the TLM marker. + * @param p_manager the user event manager. +*/ +opj_bool j2k_read_crg_v2 ( + 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; + // preconditions + assert(p_header_data != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + l_nb_comp = p_j2k->m_image->numcomps; + + if (p_header_size != l_nb_comp *4) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading CRG marker\n"); + return OPJ_FALSE; + } + /* Do not care of this at the moment since only local variables are set here */ + /* + for + (i = 0; i < l_nb_comp; ++i) + { + opj_read_bytes(p_header_data,&l_Xcrg_i,2); // Xcrg_i + p_header_data+=2; + opj_read_bytes(p_header_data,&l_Ycrg_i,2); // Xcrg_i + p_header_data+=2; + } + */ + return OPJ_TRUE; +} + static void j2k_read_tlm(opj_j2k_t *j2k) { int len, Ztlm, Stlm, ST, SP, tile_tlm, i; long int Ttlm_i, Ptlm_i; @@ -1082,6 +2315,64 @@ static void j2k_read_tlm(opj_j2k_t *j2k) { } } +/** + * Reads a TLM marker (Tile Length Marker) + * + * @param p_header_data the data contained in the TLM box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the TLM marker. + * @param p_manager the user event manager. +*/ +opj_bool j2k_read_tlm_v2 ( + 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_Ztlm, l_Stlm, l_ST, l_SP, l_tot_num_tp, l_tot_num_tp_remaining, l_quotient, l_Ptlm_size; + // preconditions + assert(p_header_data != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + if (p_header_size < 2) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading TLM marker\n"); + return OPJ_FALSE; + } + p_header_size -= 2; + + opj_read_bytes(p_header_data,&l_Ztlm,1); /* Ztlm */ + ++p_header_data; + opj_read_bytes(p_header_data,&l_Stlm,1); /* Stlm */ + ++p_header_data; + + l_ST = ((l_Stlm >> 4) & 0x3); + l_SP = (l_Stlm >> 6) & 0x1; + + l_Ptlm_size = (l_SP + 1) * 2; + l_quotient = l_Ptlm_size + l_ST; + + l_tot_num_tp = p_header_size / l_quotient; + l_tot_num_tp_remaining = p_header_size % l_quotient; + + if (l_tot_num_tp_remaining != 0) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading TLM marker\n"); + return OPJ_FALSE; + } + /* Do not care of this at the moment since only local variables are set here */ + /* + for + (i = 0; i < l_tot_num_tp; ++i) + { + opj_read_bytes(p_header_data,&l_Ttlm_i,l_ST); // Ttlm_i + p_header_data += l_ST; + opj_read_bytes(p_header_data,&l_Ptlm_i,l_Ptlm_size); // Ptlm_i + p_header_data += l_Ptlm_size; + }*/ + return OPJ_TRUE; +} + static void j2k_read_plm(opj_j2k_t *j2k) { int len, i, Zplm, Nplm, add, packet_len = 0; @@ -1107,6 +2398,77 @@ static void j2k_read_plm(opj_j2k_t *j2k) { } } +/** + * Reads a PLM marker (Packet length, main header marker) + * + * @param p_header_data the data contained in the TLM box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the TLM marker. + * @param p_manager the user event manager. +*/ +opj_bool j2k_read_plm_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 (p_header_size < 1) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading PLM marker\n"); + return OPJ_FALSE; + } + /* Do not care of this at the moment since only local variables are set here */ + /* + opj_read_bytes(p_header_data,&l_Zplm,1); // Zplm + ++p_header_data; + --p_header_size; + + while + (p_header_size > 0) + { + opj_read_bytes(p_header_data,&l_Nplm,1); // Nplm + ++p_header_data; + p_header_size -= (1+l_Nplm); + if + (p_header_size < 0) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading PLM marker\n"); + return false; + } + for + (i = 0; i < l_Nplm; ++i) + { + opj_read_bytes(p_header_data,&l_tmp,1); // Iplm_ij + ++p_header_data; + // 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 + l_packet_len = 0; + } + } + if + (l_packet_len != 0) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading PLM marker\n"); + return false; + } + } + */ + return OPJ_TRUE; +} + static void j2k_read_plt(opj_j2k_t *j2k) { int len, i, Zplt, packet_len = 0, add; @@ -1124,6 +2486,59 @@ static void j2k_read_plt(opj_j2k_t *j2k) { } } +/** + * Reads a PLT marker (Packet length, tile-part header) + * + * @param p_header_data the data contained in the PLT box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the PLT marker. + * @param p_manager the user event manager. +*/ +opj_bool j2k_read_plt_v2 ( + 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_Zplt, l_tmp, l_packet_len = 0, i; + + // 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"); + return OPJ_FALSE; + } + + opj_read_bytes(p_header_data,&l_Zplt,1); // Zplt + ++p_header_data; + --p_header_size; + + for (i = 0; i < p_header_size; ++i) { + opj_read_bytes(p_header_data,&l_tmp,1); // Iplm_ij + ++p_header_data; + // 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 + l_packet_len = 0; + } + } + + if (l_packet_len != 0) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading PLM marker\n"); + return OPJ_FALSE; + } + + return OPJ_TRUE; +} + static void j2k_read_ppm(opj_j2k_t *j2k) { int len, Z_ppm, i, j; int N_ppm; @@ -1181,6 +2596,108 @@ static void j2k_read_ppm(opj_j2k_t *j2k) { cp->ppm_store = j; } } +/** + * Reads a PPM marker (Packed packet headers, main header) + * + * @param p_header_data the data contained in the POC box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the POC marker. + * @param p_manager the user event manager. +*/ +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 + ) +{ + + opj_cp_v2_t *l_cp = 00; + OPJ_UINT32 l_remaining_data, l_Z_ppm, l_N_ppm; + + // 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 RGN marker\n"); + return OPJ_FALSE; + } + + l_cp = &(p_j2k->m_cp); + l_cp->ppm = 1; + + opj_read_bytes(p_header_data,&l_Z_ppm,1); /* Z_ppm */ + ++p_header_data; + --p_header_size; + + // 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"); + return OPJ_FALSE; + } + + // read a N_ppm + opj_read_bytes(p_header_data,&l_N_ppm,4); /* N_ppm */ + p_header_data+=4; + p_header_size-=4; + /* First PPM marker */ + l_cp->ppm_len = l_N_ppm; + l_cp->ppm_data_size = 0; + l_cp->ppm_buffer = (OPJ_BYTE *) opj_malloc(l_cp->ppm_len); + l_cp->ppm_data = l_cp->ppm_buffer; + + if (l_cp->ppm_buffer == 00) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Not enough memory reading ppm marker\n"); + return OPJ_FALSE; + } + memset(l_cp->ppm_buffer,0,l_cp->ppm_len); + } + + while (1) { + if (l_cp->ppm_data_size == l_cp->ppm_len) { + if (p_header_size >= 4) { + // read a N_ppm + opj_read_bytes(p_header_data,&l_N_ppm,4); /* N_ppm */ + p_header_data+=4; + p_header_size-=4; + l_cp->ppm_len += l_N_ppm ; + l_cp->ppm_buffer = (OPJ_BYTE *) opj_realloc(l_cp->ppm_buffer, l_cp->ppm_len); + l_cp->ppm_data = l_cp->ppm_buffer; + + if (l_cp->ppm_buffer == 00) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Not enough memory reading ppm marker\n"); + return OPJ_FALSE; + } + memset(l_cp->ppm_buffer+l_cp->ppm_data_size,0,l_N_ppm); + } + else { + return OPJ_FALSE; + } + } + + l_remaining_data = l_cp->ppm_len - l_cp->ppm_data_size; + + if (l_remaining_data <= p_header_size) { + /* we must store less information than available in the packet */ + memcpy(l_cp->ppm_buffer + l_cp->ppm_data_size , p_header_data , l_remaining_data); + l_cp->ppm_data_size = l_cp->ppm_len; + p_header_size -= l_remaining_data; + p_header_data += l_remaining_data; + } + else { + memcpy(l_cp->ppm_buffer + l_cp->ppm_data_size , p_header_data , p_header_size); + l_cp->ppm_data_size += p_header_size; + p_header_data += p_header_size; + p_header_size = 0; + break; + } + } + + return OPJ_TRUE; +} static void j2k_read_ppt(opj_j2k_t *j2k) { int len, Z_ppt, i, j = 0; @@ -1210,6 +2727,76 @@ static void j2k_read_ppt(opj_j2k_t *j2k) { tcp->ppt_store = j; } +/** + * Reads a PPT marker (Packed packet headers, tile-part header) + * + * @param p_header_data the data contained in the PPT box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the PPT marker. + * @param p_manager the user event manager. +*/ +opj_bool j2k_read_ppt_v2 ( + opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ) +{ + + opj_cp_v2_t *l_cp = 00; + opj_tcp_v2_t *l_tcp = 00; + OPJ_UINT32 l_Z_ppt; + + // 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 PPT marker\n"); + return OPJ_FALSE; + } + + l_cp = &(p_j2k->m_cp); + l_tcp = &(l_cp->tcps[p_j2k->m_current_tile_number]); + l_tcp->ppt = 1; + + opj_read_bytes(p_header_data,&l_Z_ppt,1); /* Z_ppt */ + ++p_header_data; + --p_header_size; + + // first PPM marker + if (l_Z_ppt == 0) { + /* First PPM marker */ + l_tcp->ppt_len = p_header_size; + l_tcp->ppt_data_size = 0; + l_tcp->ppt_buffer = (OPJ_BYTE *) opj_malloc(l_tcp->ppt_len); + l_tcp->ppt_data = l_tcp->ppt_buffer; + + if (l_tcp->ppt_buffer == 00) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Not enough memory reading PPT marker\n"); + return OPJ_FALSE; + } + memset(l_tcp->ppt_buffer,0,l_tcp->ppt_len); + } + else { + l_tcp->ppt_len += p_header_size; + l_tcp->ppt_buffer = (OPJ_BYTE *) opj_realloc(l_tcp->ppt_buffer,l_tcp->ppt_len); + + if (l_tcp->ppt_buffer == 00) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Not enough memory reading PPT marker\n"); + return OPJ_FALSE; + } + + l_tcp->ppt_data = l_tcp->ppt_buffer; + memset(l_tcp->ppt_buffer+l_tcp->ppt_data_size,0,p_header_size); + } + memcpy(l_tcp->ppt_buffer+l_tcp->ppt_data_size,p_header_data,p_header_size); + + l_tcp->ppt_data_size += p_header_size; + return OPJ_TRUE; +} + static void j2k_write_tlm(opj_j2k_t *j2k){ int lenp; opj_cio_t *cio = j2k->cio; @@ -1382,6 +2969,170 @@ static void j2k_read_sot(opj_j2k_t *j2k) { } } +/** + * Reads a PPT marker (Packed packet headers, tile-part header) + * + * @param p_header_data the data contained in the PPT box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the PPT marker. + * @param p_manager the user event manager. +*/ +opj_bool j2k_read_sot_v2 ( + opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ) +{ + + opj_cp_v2_t *l_cp = 00; + opj_tcp_v2_t *l_tcp = 00; + OPJ_UINT32 l_tot_len, l_num_parts = 0; + OPJ_UINT32 l_current_part; + OPJ_UINT32 l_tile_x,l_tile_y; + + // preconditions + assert(p_header_data != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + if (p_header_size != 8) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading SOT marker\n"); + return OPJ_FALSE; + } + + l_cp = &(p_j2k->m_cp); + opj_read_bytes(p_header_data,&(p_j2k->m_current_tile_number),2); /* Isot */ + p_header_data+=2; + + l_tcp = &l_cp->tcps[p_j2k->m_current_tile_number]; + l_tile_x = p_j2k->m_current_tile_number % l_cp->tw; + l_tile_y = p_j2k->m_current_tile_number / l_cp->tw; + +#ifdef USE_JPWL + if (p_j2k->m_cp->correct) { + + static int backup_tileno = 0; + + /* tileno is negative or larger than the number of tiles!!! */ + if ((tileno < 0) || (tileno > (cp->tw * cp->th))) { + opj_event_msg(p_j2k->cinfo, EVT_ERROR, + "JPWL: bad tile number (%d out of a maximum of %d)\n", + tileno, (cp->tw * cp->th)); + if (!JPWL_ASSUME) { + opj_event_msg(p_j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + /* we try to correct */ + tileno = backup_tileno; + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- trying to adjust this\n" + "- setting tile number to %d\n", + tileno); + } + + /* keep your private count of tiles */ + backup_tileno++; + }; +#endif /* USE_JPWL */ + + /* look for the tile in the list of already processed tile (in parts). */ + /* Optimization possible here with a more complex data structure and with the removing of tiles */ + /* since the time taken by this function can only grow at the time */ + + opj_read_bytes(p_header_data,&l_tot_len,4); /* Psot */ + p_header_data+=4; + +#ifdef USE_JPWL + if (p_j2k->m_cp->correct) { + + /* totlen is negative or larger than the bytes left!!! */ + if ((totlen < 0) || (totlen > (p_stream_numbytesleft(p_stream) + 8))) { + opj_event_msg(p_j2k->cinfo, EVT_ERROR, + "JPWL: bad tile byte size (%d bytes against %d bytes left)\n", + totlen, p_stream_numbytesleft(p_stream) + 8); + if (!JPWL_ASSUME) { + opj_event_msg(p_j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + /* we try to correct */ + totlen = 0; + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- trying to adjust this\n" + "- setting Psot to %d => assuming it is the last tile\n", + totlen); + } + + }; +#endif /* USE_JPWL */ + + if (!l_tot_len) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Cannot read data with no size known, giving up\n"); + return OPJ_FALSE; + } + + opj_read_bytes(p_header_data,&l_current_part ,1); /* Psot */ + ++p_header_data; + + opj_read_bytes(p_header_data,&l_num_parts ,1); /* Psot */ + ++p_header_data; + + if (l_num_parts != 0) { + l_tcp->m_nb_tile_parts = l_num_parts; + } + + if (l_tcp->m_nb_tile_parts) { + if (l_tcp->m_nb_tile_parts == (l_current_part + 1)) { + p_j2k->m_specific_param.m_decoder.m_can_decode = 1; + } + } + + p_j2k->m_specific_param.m_decoder.m_sot_length = l_tot_len - 12; + p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_TPH;// FIXME J2K_DEC_STATE_TPH; + p_j2k->m_specific_param.m_decoder.m_skip_data = + (l_tile_x < p_j2k->m_specific_param.m_decoder.m_start_tile_x) + || (l_tile_x >= p_j2k->m_specific_param.m_decoder.m_end_tile_x) + || (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); + + /* Index */ + + /* move this onto a separate method to call before reading any SOT */ + /*if + TODO + (p_j2k->cstr_info) + { + if + (l_tcp->first) + { + if + (tileno == 0) + { + p_j2k->cstr_info->main_head_end = p_stream_tell(p_stream) - 13; + } + p_j2k->cstr_info->tile[tileno].tileno = tileno; + p_j2k->cstr_info->tile[tileno].start_pos = p_stream_tell(p_stream) - 12; + p_j2k->cstr_info->tile[tileno].end_pos = p_j2k->cstr_info->tile[tileno].start_pos + totlen - 1; + p_j2k->cstr_info->tile[tileno].num_tps = numparts; + if + (numparts) + { + p_j2k->cstr_info->tile[tileno].tp = (opj_tp_info_t *) opj_malloc(numparts * sizeof(opj_tp_info_t)); + } + else + { + p_j2k->cstr_info->tile[tileno].tp = (opj_tp_info_t *) opj_malloc(10 * sizeof(opj_tp_info_t)); // Fixme (10) + } + } + else + { + p_j2k->cstr_info->tile[tileno].end_pos += totlen; + } + p_j2k->cstr_info->tile[tileno].tp[partno].tp_start_pos = p_stream_tell(p_stream) - 12; + p_j2k->cstr_info->tile[tileno].tp[partno].tp_end_pos = + p_j2k->cstr_info->tile[tileno].tp[partno].tp_start_pos + totlen - 1; + }*/ + return OPJ_TRUE; +} + static void j2k_write_sod(opj_j2k_t *j2k, void *tile_coder) { int l, layno; int totlen; @@ -1496,6 +3247,77 @@ static void j2k_read_sod(opj_j2k_t *j2k) { j2k->cur_tp_num++; } +/** + * Reads a SOD marker (Start Of Data) + * + * @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. +*/ +opj_bool j2k_read_sod_v2 ( + opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 l_current_read_size; + opj_codestream_info_t * l_cstr_info = 00; + OPJ_BYTE ** l_current_data = 00; + opj_tcp_v2_t * l_tcp = 00; + OPJ_UINT32 * l_tile_len = 00; + + // 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]); + p_j2k->m_specific_param.m_decoder.m_sot_length -= 2; + l_cstr_info = p_j2k->cstr_info; + + l_current_data = &(l_tcp->m_data); + l_tile_len = &l_tcp->m_data_size; + + if (! *l_current_data) { + *l_current_data = (OPJ_BYTE*) opj_malloc/*FIXME V2 -> my_opj_malloc*/(p_j2k->m_specific_param.m_decoder.m_sot_length); + } + else { + *l_current_data = (OPJ_BYTE*) opj_realloc/*FIXME V2 -> my_opj_realloc*/(*l_current_data, *l_tile_len + p_j2k->m_specific_param.m_decoder.m_sot_length); + } + + if (*l_current_data == 00) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Cannot decode tile\n"); + return OPJ_FALSE; + } + + /* Index */ + if (l_cstr_info) { + OPJ_SIZE_T l_current_pos = opj_stream_tell(p_stream)-1; + l_cstr_info->tile[p_j2k->m_current_tile_number].tp[p_j2k->m_specific_param.m_encoder.m_current_tile_part_number].tp_end_header = l_current_pos; + + if (p_j2k->m_specific_param.m_encoder.m_current_tile_part_number == 0) { + l_cstr_info->tile[p_j2k->m_current_tile_number].end_header = l_current_pos; + } + + l_cstr_info->packno = 0; + } + + l_current_read_size = opj_stream_read_data(p_stream, *l_current_data + *l_tile_len , p_j2k->m_specific_param.m_decoder.m_sot_length,p_manager); + + if (l_current_read_size != p_j2k->m_specific_param.m_decoder.m_sot_length) { + p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_NEOC; // FIXME J2K_DEC_STATE_NEOC; + } + else { + p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_TPHSOT; // FIXME J2K_DEC_STATE_TPHSOT; + } + + *l_tile_len += l_current_read_size; + + return OPJ_TRUE; +} + + static void j2k_write_rgn(opj_j2k_t *j2k, int compno, int tileno) { opj_cp_t *cp = j2k->cp; opj_tcp_t *tcp = &cp->tcps[tileno]; @@ -1552,6 +3374,80 @@ static void j2k_write_eoc(opj_j2k_t *j2k) { /* <m_image; + l_nb_comp = l_image->numcomps; + + if (l_nb_comp <= 256) { + l_comp_room = 1; + } + else { + l_comp_room = 2; + } + + if (p_header_size != 2 + l_comp_room) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading RGN marker\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; + + opj_read_bytes(p_header_data,&l_comp_no,l_comp_room); /* Crgn */ + p_header_data+=l_comp_room; + opj_read_bytes(p_header_data,&l_roi_sty,1); /* Srgn */ + ++p_header_data; + +#ifdef USE_JPWL + if (p_j2k->m_cp->correct) { + /* totlen is negative or larger than the bytes left!!! */ + if (compno >= numcomps) { + opj_event_msg(p_j2k->cinfo, EVT_ERROR, + "JPWL: bad component number in RGN (%d when there are only %d)\n", + compno, numcomps); + if (!JPWL_ASSUME || JPWL_ASSUME) { + opj_event_msg(p_j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + } + }; +#endif /* USE_JPWL */ + + opj_read_bytes(p_header_data,(OPJ_UINT32 *) (&(l_tcp->tccps[l_comp_no].roishift)),1); /* SPrgn */ + ++p_header_data; + + return OPJ_TRUE; + +} + static void j2k_read_eoc(opj_j2k_t *j2k) { int i, tileno; opj_bool success; @@ -2513,6 +4409,7 @@ static void j2k_add_mhmarker(opj_codestream_info_t *cstr_info, unsigned short in 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; if (!cstr_info) @@ -2532,3 +4429,1322 @@ static void j2k_add_tlmarker( int tileno, opj_codestream_info_t *cstr_info, unsi marker->len = len; cstr_info->tile[tileno].marknum++; } + + + +/* + * ----------------------------------------------------------------------- + * ----------------------------------------------------------------------- + * ----------------------------------------------------------------------- + */ + +/** + * Ends the decompression procedures and possibiliy add data to be read after the + * codestream. + */ +opj_bool j2k_end_decompress( + opj_j2k_t *p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * 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( + opj_j2k_v2_t *p_j2k, + struct opj_image ** p_image, + OPJ_INT32 * p_tile_x0, + OPJ_INT32 * p_tile_y0, + OPJ_UINT32 * p_tile_width, + OPJ_UINT32 * p_tile_height, + OPJ_UINT32 * p_nb_tiles_x, + OPJ_UINT32 * p_nb_tiles_y, + 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); + + + *p_image = 00; + /* create an empty image */ + p_j2k->m_image = opj_image_create0(); + if + (! p_j2k->m_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_image); + p_j2k->m_image = 00; + 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_image); + p_j2k->m_image = 00; + return OPJ_FALSE; + } + *p_image = p_j2k->m_image; + * p_tile_x0 = p_j2k->m_cp.tx0; + * p_tile_y0 = p_j2k->m_cp.ty0; + * p_tile_width = p_j2k->m_cp.tdx; + * p_tile_height = p_j2k->m_cp.tdy; + * p_nb_tiles_x = p_j2k->m_cp.tw; + * p_nb_tiles_y = p_j2k->m_cp.th; + 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,(void*)j2k_read_header_procedure); + + /* DEVELOPER CORNER, add your custom procedures */ + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)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, (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 */ + +} + +/** + * 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. + * + * @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); + + p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_MHSOC; // The codestream must begin with SOC marker FIXME J2K_DEC_STATE_MHSOC + + // Try to read the 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) { + // 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 + + 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); + + // 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; + } + + // 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; + } + + // 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); + } + + p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_TPHSOT; // FIXME J2K_DEC_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_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 + (i=0;itccps; + memcpy(l_tcp,l_default_tcp, sizeof(opj_tcp_v2_t)); + l_tcp->ppt = 0; + l_tcp->ppt_data = 00; + l_tcp->tccps = l_current_tccp; + 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); + } + 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); + 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; + } + 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_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; + } + memcpy(l_current_tccp,l_default_tcp->tccps,l_tccp_size); + ++l_tcp; + } + 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; +#ifdef TOTO_MSD + opj_event_msg(p_manager, EVT_ERROR, "Cannot decode tile, memory error\n"); +#endif + 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 (const 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_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; + + opj_free(p_j2k); +} + + + +/** + * 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; + } + if + (p_tcp->m_data) + { + opj_free(p_tcp->m_data); + p_tcp->m_data = 00; + } +} + + +/** + * 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 = 00; + OPJ_UINT32 l_nb_tiles; + + // preconditions + assert(p_stream != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + if + (p_j2k->m_specific_param.m_decoder.m_state == 0x0100)// FIXME J2K_DEC_STATE_EOC) + { + l_current_marker = J2K_MS_EOC; + } + else if + (p_j2k->m_specific_param.m_decoder.m_state != J2K_STATE_TPHSOT) // FIXME J2K_DEC_STATE_TPHSOT) + { + return OPJ_FALSE; + } + + while + (! p_j2k->m_specific_param.m_decoder.m_can_decode && l_current_marker != J2K_MS_EOC) + { + while + (l_current_marker != J2K_MS_SOD) + { + 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_j2k->m_specific_param.m_decoder.m_header_data,&l_marker_size,2); + if + (p_j2k->m_specific_param.m_decoder.m_state & J2K_STATE_TPH) // FIXME J2K_DEC_STATE_TPH) + { + p_j2k->m_specific_param.m_decoder.m_sot_length -= (l_marker_size + 2); + } + l_marker_size -= 2; + + l_marker_handler = j2k_get_marker_handler(l_current_marker); + // Check if the marker is known + 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; + } + 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; + + } + 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; + } + 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 is not compliant with its position\n"); + return OPJ_FALSE; + } + if + (p_j2k->m_specific_param.m_decoder.m_skip_data) + { + 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; + } + else + { + 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_j2k->m_specific_param.m_decoder.m_header_data,&l_current_marker,2); + } + } + + if + (! p_j2k->m_specific_param.m_decoder.m_skip_data) + { + if + (! j2k_read_sod_v2(p_j2k,p_stream,p_manager)) + { + return OPJ_FALSE; + } + } + else + { + 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; // FIXME J2K_DEC_STATE_TPHSOT; + 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_j2k->m_specific_param.m_decoder.m_header_data,&l_current_marker,2); + } + } + + if + (l_current_marker == J2K_MS_EOC) + { + if + (p_j2k->m_specific_param.m_decoder.m_state != 0x0100 )// FIXME J2K_DEC_STATE_EOC) + { + p_j2k->m_current_tile_number = 0; + p_j2k->m_specific_param.m_decoder.m_state = 0x0100;// FIXMEJ2K_DEC_STATE_EOC; + } + } + 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; + while + ( + (p_j2k->m_current_tile_number < l_nb_tiles) + && (l_tcp->m_data == 00) + ) + { + ++p_j2k->m_current_tile_number; + ++l_tcp; + } + if + (p_j2k->m_current_tile_number == l_nb_tiles) + { + *p_go_on = OPJ_FALSE; + return OPJ_TRUE; + } + } + 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; + } + *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; + 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 + ) +{ + OPJ_UINT32 l_current_marker; + OPJ_BYTE l_data [2]; + opj_tcp_v2_t * l_tcp; + + // 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; + } + l_tcp = &(p_j2k->m_cp.tcps[p_tile_index]); + if + (! l_tcp->m_data) + { + j2k_tcp_destroy(&(p_j2k->m_cp.tcps[p_tile_index])); + 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_info)) + { + 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; + } + j2k_tcp_destroy(l_tcp); + p_j2k->m_tcd->tcp = 0; + + 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); + 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; + } + } + return OPJ_TRUE; +} + + +/** + * 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 + * + * @return true if the area could be set. + */ +opj_bool j2k_set_decode_area( + opj_j2k_v2_t *p_j2k, + 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_cp_v2_t * l_cp = &(p_j2k->m_cp); + + if + (p_j2k->m_specific_param.m_decoder.m_state != J2K_STATE_TPHSOT)// FIXME J2K_DEC_STATE_TPHSOT) + { + return OPJ_FALSE; + } + p_j2k->m_specific_param.m_decoder.m_start_tile_x = (p_start_x - l_cp->tx0) / l_cp->tdx; + p_j2k->m_specific_param.m_decoder.m_start_tile_y = (p_start_y - l_cp->ty0) / l_cp->tdy; + p_j2k->m_specific_param.m_decoder.m_end_tile_x = int_ceildiv((p_end_x - l_cp->tx0), l_cp->tdx); + p_j2k->m_specific_param.m_decoder.m_end_tile_y = int_ceildiv((p_end_y - l_cp->ty0), l_cp->tdy); + p_j2k->m_specific_param.m_decoder.m_discard_tiles = 1; + return OPJ_TRUE; +} + + +/* ----------------------------------------------------------------------- */ +/* J2K / JPT decoder interface */ +/* ----------------------------------------------------------------------- */ +/** + * Creates a J2K decompression structure. + * + * @return a handle to a J2K decompressor if successful, NULL otherwise. +*/ +opj_j2k_v2_t* j2k_create_decompress_v2() +{ + 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)); + l_j2k->m_is_decoder = 1; + l_j2k->m_cp.m_is_decoder = 1; + 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) + { + opj_free(l_j2k); + return 00; + } + 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; + } + l_j2k->m_specific_param.m_decoder.m_header_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 00; + } + + // 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 l_j2k; +} + + +/** + * 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; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_header_data != 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; + + // precondition again + assert(compno < p_j2k->m_image->numcomps); + + l_tccp = &l_tcp->tccps[compno]; + l_current_ptr = p_header_data; + + // 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; + } + opj_read_bytes(l_current_ptr, &l_tccp->numresolutions ,1); /* SPcox (D) */ + ++l_tccp->numresolutions; /* tccp->numresolutions = read() + 1 */ + ++l_current_ptr; + + // 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; + } + + opj_read_bytes(l_current_ptr,&l_tccp->cblkw ,1); /* SPcoc (E) */ + ++l_current_ptr; + l_tccp->cblkw += 2; + + opj_read_bytes(l_current_ptr,&l_tccp->cblkh ,1); /* SPcoc (F) */ + ++l_current_ptr; + l_tccp->cblkh += 2; + + opj_read_bytes(l_current_ptr,&l_tccp->cblksty ,1); /* SPcoc (G) */ + ++l_current_ptr; + + 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"); + 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; + } + *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; + } + } + + /* INDEX >> */ + if (p_j2k->cstr_info && compno == 0) { + OPJ_UINT32 l_data_size = l_tccp->numresolutions * sizeof(OPJ_UINT32); + 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 */ + return OPJ_TRUE; +} + +/** + * Copies the tile component parameters of all the component from the first tile component. + * + * @param p_j2k the J2k codec. + */ +void j2k_copy_tile_component_parameters( 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; + opj_tccp_t *l_copied_tccp = NULL; + OPJ_UINT32 l_prc_size; + + // 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); + + for (i=1;im_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 + ) +{ + // 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; + OPJ_UINT32 l_num_band; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_header_data != 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; + // precondition again + assert(p_comp_no < p_j2k->m_image->numcomps); + + l_tccp = &l_tcp->tccps[p_comp_no]; + l_current_ptr = p_header_data; + + 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; + + opj_read_bytes(l_current_ptr, &l_tmp ,1); /* Sqcx */ + ++l_current_ptr; + + 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( l_num_band > J2K_MAXBANDS ) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading CCP_QNTSTY element\n"); + return OPJ_FALSE; + } + } + +#ifdef USE_JPWL + if (p_j2k->m_cp->correct) { + + /* if JPWL is on, we check whether there are too many subbands */ + if ((numbands < 0) || (numbands >= J2K_MAXBANDS)) { + opj_event_msg(p_j2k->cinfo, JPWL_ASSUME ? EVT_WARNING : EVT_ERROR, + "JPWL: bad number of subbands in Sqcx (%d)\n", + numbands); + if (!JPWL_ASSUME) { + opj_event_msg(p_j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + /* we try to correct */ + numbands = 1; + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- trying to adjust them\n" + "- setting number of bands to %d => HYPOTHESIS!!!\n", + numbands); + }; + + }; +#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; + l_tccp->stepsizes[l_band_no].expn = l_tmp>>3; + l_tccp->stepsizes[l_band_no].mant = 0; + } + *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; + 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; +} + + + +/** + * 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; + 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 + 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; + // precondition again + 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_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; + } +} + + /* add the marker */ + marker->type = type; + marker->pos = pos; + marker->len = len; + cstr_info->tile[tileno].marknum++; +} diff --git a/libopenjpeg/j2k.h b/libopenjpeg/j2k.h index 6338c290..0b8f30d6 100644 --- a/libopenjpeg/j2k.h +++ b/libopenjpeg/j2k.h @@ -77,6 +77,14 @@ The functions in J2K.C have for goal to read/write the several parts of the code #define J2K_MS_EPH 0xff92 /**< EPH marker value */ #define J2K_MS_CRG 0xff63 /**< CRG marker value */ #define J2K_MS_COM 0xff64 /**< COM marker value */ + +#ifdef TODO_MS +#define J2K_MS_CBD 0xff78 /**< CBD marker value */ +#define J2K_MS_MCC 0xff75 /**< MCC marker value */ +#define J2K_MS_MCT 0xff74 /**< MCT marker value */ +#define J2K_MS_MCO 0xff77 /**< MCO marker value */ +#endif + /* UniPG>> */ #ifdef USE_JPWL #define J2K_MS_EPC 0xff68 /**< EPC marker value (Part 11: JPEG 2000 for Wireless) */ @@ -91,6 +99,8 @@ The functions in J2K.C have for goal to read/write the several parts of the code /* < there was a PPT marker for the present tile */ + OPJ_UINT32 ppt : 1; + /** indicates if a POC marker has been used O:NO, 1:YES */ + OPJ_UINT32 POC : 1; +} opj_tcp_v2_t; + + + + + /** Coding parameters */ @@ -308,6 +467,198 @@ typedef struct opj_cp { /* <> */ +#ifdef USE_JPWL + /** enables writing of EPC in MH, thus activating JPWL */ + bool epc_on; + /** enables writing of EPB, in case of activated JPWL */ + bool epb_on; + /** enables writing of ESD, in case of activated JPWL */ + bool esd_on; + /** enables writing of informative techniques of ESD, in case of activated JPWL */ + bool info_on; + /** enables writing of RED, in case of activated JPWL */ + bool red_on; + /** error protection method for MH (0,1,16,32,37-128) */ + int hprot_MH; + /** tile number of header protection specification (>=0) */ + int hprot_TPH_tileno[JPWL_MAX_NO_TILESPECS]; + /** error protection methods for TPHs (0,1,16,32,37-128) */ + int hprot_TPH[JPWL_MAX_NO_TILESPECS]; + /** tile number of packet protection specification (>=0) */ + int pprot_tileno[JPWL_MAX_NO_PACKSPECS]; + /** packet number of packet protection specification (>=0) */ + int pprot_packno[JPWL_MAX_NO_PACKSPECS]; + /** error protection methods for packets (0,1,16,32,37-128) */ + int pprot[JPWL_MAX_NO_PACKSPECS]; + /** enables writing of ESD, (0/2/4 bytes) */ + int sens_size; + /** sensitivity addressing size (0=auto/2/4 bytes) */ + int sens_addr; + /** sensitivity range (0-3) */ + int sens_range; + /** sensitivity method for MH (-1,0-7) */ + int sens_MH; + /** tile number of sensitivity specification (>=0) */ + int sens_TPH_tileno[JPWL_MAX_NO_TILESPECS]; + /** sensitivity methods for TPHs (-1,0-7) */ + int sens_TPH[JPWL_MAX_NO_TILESPECS]; + /** enables JPWL correction at the decoder */ + bool correct; + /** expected number of components at the decoder */ + int exp_comps; + /** maximum number of tiles at the decoder */ + int max_tiles; +#endif /* USE_JPWL */ + + /******** FLAGS *********/ + /** if ppm == 1 --> there was a PPM marker*/ + OPJ_UINT32 ppm : 1; + /** tells if the parameter is a coding or decoding one */ + OPJ_UINT32 m_is_decoder : 1; +/* < V1 cf below +} + +void set_default_event_handler(opj_event_mgr_t * p_manager) +{ + //FIXME V2 -> V1 + //p_manager->m_error_data = 00; + //p_manager->m_warning_data = 00; + //p_manager->m_info_data = 00; + p_manager->error_handler = opj_default_callback; + p_manager->info_handler = opj_default_callback; + p_manager->warning_handler = opj_default_callback; +} + +OPJ_UINT32 opj_read_from_file (void * p_buffer, OPJ_UINT32 p_nb_bytes, FILE * p_file) +{ + OPJ_UINT32 l_nb_read = fread(p_buffer,1,p_nb_bytes,p_file); + return l_nb_read ? l_nb_read : -1; +} + +OPJ_UINT32 opj_write_from_file (void * p_buffer, OPJ_UINT32 p_nb_bytes, FILE * p_file) +{ + return fwrite(p_buffer,1,p_nb_bytes,p_file); +} + +OPJ_SIZE_T opj_skip_from_file (OPJ_SIZE_T p_nb_bytes, FILE * p_user_data) +{ + if + (fseek(p_user_data,p_nb_bytes,SEEK_CUR)) + { + return -1; + } + return p_nb_bytes; +} + +opj_bool opj_seek_from_file (OPJ_SIZE_T p_nb_bytes, FILE * p_user_data) +{ + if + (fseek(p_user_data,p_nb_bytes,SEEK_SET)) + { + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} + /* ---------------------------------------------------------------------- */ #ifdef _WIN32 #ifndef OPJ_STATIC @@ -95,6 +205,120 @@ opj_dinfo_t* OPJ_CALLCONV opj_create_decompress(OPJ_CODEC_FORMAT format) { return dinfo; } +opj_codec_t* OPJ_CALLCONV opj_create_decompress_v2(OPJ_CODEC_FORMAT p_format) +{ + opj_codec_private_t *l_info = 00; + + l_info = (opj_codec_private_t*) opj_calloc(1, sizeof(opj_codec_private_t)); + if (!l_info){ + return 00; + } + memset(l_info, 0, sizeof(opj_codec_private_t)); + + l_info->is_decompressor = 1; + + switch + (p_format) + { + case CODEC_J2K: + l_info->m_codec_data.m_decompression.opj_decode = (opj_image_t* (*) (void *, struct opj_stream_private *, struct opj_event_mgr * ))j2k_decode; + l_info->m_codec_data.m_decompression.opj_end_decompress = (opj_bool (*) (void *,struct opj_stream_private *,struct opj_event_mgr *))j2k_end_decompress; + l_info->m_codec_data.m_decompression.opj_read_header = (opj_bool (*) ( + void *, + opj_image_t **, + OPJ_INT32 * , + OPJ_INT32 * , + OPJ_UINT32 * , + OPJ_UINT32 * , + OPJ_UINT32 * , + OPJ_UINT32 * , + struct opj_stream_private *, + struct opj_event_mgr * )) j2k_read_header; + l_info->m_codec_data.m_decompression.opj_destroy = (void (*) (void *))j2k_destroy; + l_info->m_codec_data.m_decompression.opj_setup_decoder = (void (*) (void * ,opj_dparameters_t * )) j2k_setup_decoder; + l_info->m_codec_data.m_decompression.opj_read_tile_header = (opj_bool (*) ( + void *, + OPJ_UINT32*, + OPJ_UINT32*, + OPJ_INT32 * , + OPJ_INT32 * , + OPJ_INT32 * , + OPJ_INT32 * , + OPJ_UINT32 * , + opj_bool *, + struct opj_stream_private *, + struct opj_event_mgr * )) j2k_read_tile_header; + l_info->m_codec_data.m_decompression.opj_decode_tile_data = (opj_bool (*) (void *,OPJ_UINT32,OPJ_BYTE*,OPJ_UINT32,struct opj_stream_private *, struct opj_event_mgr * )) j2k_decode_tile; + l_info->m_codec_data.m_decompression.opj_set_decode_area = (opj_bool (*) (void *,OPJ_INT32,OPJ_INT32,OPJ_INT32,OPJ_INT32, struct opj_event_mgr * )) j2k_set_decode_area; + l_info->m_codec = j2k_create_decompress_v2(); + if + (! l_info->m_codec) + { + opj_free(l_info); + return 00; + } + break; + + case CODEC_JP2: + /* get a JP2 decoder handle */ +#ifdef TODO_MSD + l_info->m_codec_data.m_decompression.opj_decode = (opj_image_t* (*) (void *, struct opj_stream_private *, struct opj_event_mgr * ))opj_jp2_decode; + l_info->m_codec_data.m_decompression.opj_end_decompress = (opj_bool (*) (void *,struct opj_stream_private *,struct opj_event_mgr *)) jp2_end_decompress; + l_info->m_codec_data.m_decompression.opj_read_header = (opj_bool (*) ( + void *, + opj_image_t **, + + OPJ_INT32 * , + OPJ_INT32 * , + OPJ_UINT32 * , + OPJ_UINT32 * , + OPJ_UINT32 * , + OPJ_UINT32 * , + struct opj_stream_private *, + struct opj_event_mgr * )) jp2_read_header; + + l_info->m_codec_data.m_decompression.opj_read_tile_header = ( + opj_bool (*) ( + void *, + OPJ_UINT32*, + OPJ_UINT32*, + OPJ_INT32*, + OPJ_INT32*, + OPJ_INT32 * , + OPJ_INT32 * , + OPJ_UINT32 * , + opj_bool *, + struct opj_stream_private *, + struct opj_event_mgr * )) jp2_read_tile_header; + + l_info->m_codec_data.m_decompression.opj_decode_tile_data = (opj_bool (*) (void *,OPJ_UINT32,OPJ_BYTE*,OPJ_UINT32,struct opj_stream_private *, struct opj_event_mgr * )) opj_jp2_decode_tile; + + l_info->m_codec_data.m_decompression.opj_destroy = (void (*) (void *))jp2_destroy; + l_info->m_codec_data.m_decompression.opj_setup_decoder = (void (*) (void * ,opj_dparameters_t * )) jp2_setup_decoder; + l_info->m_codec_data.m_decompression.opj_set_decode_area = (opj_bool (*) (void *,OPJ_INT32,OPJ_INT32,OPJ_INT32,OPJ_INT32, struct opj_event_mgr * )) jp2_set_decode_area; + + + l_info->m_codec = jp2_create(OPJ_TRUE); + if + (! l_info->m_codec) + { + opj_free(l_info); + return 00; + } +#endif + break; + case CODEC_UNKNOWN: + case CODEC_JPT: + default: + opj_free(l_info); + return 00; + } + + // FIXME set_default_event_handler(&(l_info->m_event_mgr)); + return (opj_codec_t*) l_info; +} + + void OPJ_CALLCONV opj_destroy_decompress(opj_dinfo_t *dinfo) { if(dinfo) { /* destroy the codec */ @@ -152,6 +376,22 @@ void OPJ_CALLCONV opj_setup_decoder(opj_dinfo_t *dinfo, opj_dparameters_t *param } } +opj_bool OPJ_CALLCONV opj_setup_decoder_v2(opj_codec_t *p_info, opj_dparameters_t *parameters, opj_event_mgr_t* event_mgr) +{ + if (p_info && parameters) { + opj_codec_private_t * l_info = (opj_codec_private_t *) p_info; + + if (! l_info->is_decompressor) { + return OPJ_FALSE; + } + + l_info->m_codec_data.m_decompression.opj_setup_decoder(l_info->m_codec,parameters); + l_info->m_event_mgr = event_mgr; + return OPJ_TRUE; + } + return OPJ_FALSE; +} + opj_image_t* OPJ_CALLCONV opj_decode(opj_dinfo_t *dinfo, opj_cio_t *cio) { return opj_decode_with_info(dinfo, cio, NULL); } @@ -284,6 +524,39 @@ void OPJ_CALLCONV opj_set_default_encoder_parameters(opj_cparameters_t *paramete } } +/** + * Helper function. + * Sets the stream to be a file stream. The FILE must have been open previously. + * @param p_stream the stream to modify + * @param p_file handler to an already open file. +*/ +opj_stream_t* OPJ_CALLCONV opj_stream_create_default_file_stream (FILE * p_file, opj_bool p_is_read_stream) +{ + return opj_stream_create_file_stream(p_file,J2K_STREAM_CHUNK_SIZE,p_is_read_stream); +} + +opj_stream_t* OPJ_CALLCONV opj_stream_create_file_stream (FILE * p_file, OPJ_UINT32 p_size, opj_bool p_is_read_stream) +{ + opj_stream_t* l_stream = 00; + if + (! p_file) + { + return 00; + } + l_stream = opj_stream_create(p_size,p_is_read_stream); + if + (! l_stream) + { + return 00; + } + opj_stream_set_user_data(l_stream,p_file); + opj_stream_set_read_function(l_stream,(opj_stream_read_fn) opj_read_from_file); + opj_stream_set_write_function(l_stream, (opj_stream_write_fn) opj_write_from_file); + opj_stream_set_skip_function(l_stream, (opj_stream_skip_fn) opj_skip_from_file); + opj_stream_set_seek_function(l_stream, (opj_stream_seek_fn) opj_seek_from_file); + return l_stream; +} + void OPJ_CALLCONV opj_setup_encoder(opj_cinfo_t *cinfo, opj_cparameters_t *parameters, opj_image_t *image) { if(cinfo && parameters && image) { switch(cinfo->codec_format) { @@ -340,3 +613,61 @@ void OPJ_CALLCONV opj_destroy_cstr_info(opj_codestream_info_t *cstr_info) { opj_free(cstr_info->numdecompos); } } + + +opj_bool OPJ_CALLCONV opj_read_header ( + opj_codec_t *p_codec, + opj_image_t ** p_image, + OPJ_INT32 * p_tile_x0, + OPJ_INT32 * p_tile_y0, + OPJ_UINT32 * p_tile_width, + OPJ_UINT32 * p_tile_height, + OPJ_UINT32 * p_nb_tiles_x, + OPJ_UINT32 * p_nb_tiles_y, + opj_stream_t *p_cio) +{ + if + (p_codec && p_cio) + { + opj_codec_private_t * l_info = (opj_codec_private_t *) p_codec; + opj_stream_private_t * l_cio = (opj_stream_private_t *) p_cio; + if + (! l_info->is_decompressor) + { + return OPJ_FALSE; + } + return l_info->m_codec_data.m_decompression.opj_read_header( + l_info->m_codec, + p_image, + p_tile_x0, + p_tile_y0, + p_tile_width, + p_tile_height, + p_nb_tiles_x, + p_nb_tiles_y, + l_cio, + //&(l_info->m_event_mgr)); + l_info->m_event_mgr); + } + return OPJ_FALSE; +} + +void OPJ_CALLCONV opj_destroy_codec(opj_codec_t *p_info) +{ + if + (p_info) + { + opj_codec_private_t * l_info = (opj_codec_private_t *) p_info; + if + (l_info->is_decompressor) + { + l_info->m_codec_data.m_decompression.opj_destroy(l_info->m_codec); + } + else + { + l_info->m_codec_data.m_compression.opj_destroy(l_info->m_codec); + } + l_info->m_codec = 00; + opj_free(l_info); + } +} diff --git a/libopenjpeg/openjpeg.h b/libopenjpeg/openjpeg.h index 51d691e6..0f35fbd3 100644 --- a/libopenjpeg/openjpeg.h +++ b/libopenjpeg/openjpeg.h @@ -64,8 +64,19 @@ typedef int opj_bool; #define OPJ_TRUE 1 #define OPJ_FALSE 0 +typedef unsigned int OPJ_UINT32; +typedef int OPJ_INT32; +typedef unsigned short OPJ_UINT16; +typedef short OPJ_INT16; +typedef char OPJ_CHAR; +typedef unsigned char OPJ_BYTE; +typedef unsigned int OPJ_SIZE_T; +typedef double OPJ_FLOAT64; +typedef float OPJ_FLOAT32; + // Avoid compile-time warning because parameter is not used #define OPJ_ARG_NOT_USED(x) (void)(x) + /* ========================================================== Useful constant definitions @@ -77,6 +88,12 @@ typedef int opj_bool; #define J2K_MAXRLVLS 33 /**< Number of maximum resolution level authorized */ #define J2K_MAXBANDS (3*J2K_MAXRLVLS-2) /**< Number of maximum sub-band linked to number of resolution level */ +#define J2K_DEFAULT_NB_SEGS 10 +#define J2K_STREAM_CHUNK_SIZE 0x100000 /** 1 mega by default */ +#define J2K_DEFAULT_HEADER_SIZE 1000 +#define J2K_MCC_DEFAULT_NB_RECORDS 10 +#define J2K_MCT_DEFAULT_NB_RECORDS 10 + /* UniPG>> */ #define JPWL_MAX_NO_TILESPECS 16 /**< Maximum number of tile parts expected by JPWL: increase at your will */ #define JPWL_MAX_NO_PACKSPECS 16 /**< Maximum number of packet parts expected by JPWL: increase at your will */ @@ -177,6 +194,7 @@ used for */ typedef struct opj_event_mgr { + void* client_data; /** Error message callback if available, NULL otherwise */ opj_msg_callback error_handler; /** Warning message callback if available, NULL otherwise */ @@ -448,6 +466,11 @@ typedef struct opj_dinfo { /* other specific fields go here */ } opj_dinfo_t; +/** + * J2k codec. + */ +typedef void * opj_codec_t; + /* ========================================================== I/O stream typedef definitions @@ -484,6 +507,14 @@ typedef struct opj_cio { unsigned char *bp; } opj_cio_t; +typedef OPJ_UINT32 (* opj_stream_read_fn) (void * p_buffer, OPJ_UINT32 p_nb_bytes, void * p_user_data) ; +typedef OPJ_UINT32 (* opj_stream_write_fn) (void * p_buffer, OPJ_UINT32 p_nb_bytes, void * p_user_data) ; +typedef OPJ_SIZE_T (* opj_stream_skip_fn) (OPJ_SIZE_T p_nb_bytes, void * p_user_data) ; +typedef opj_bool (* opj_stream_seek_fn) (OPJ_SIZE_T p_nb_bytes, void * p_user_data) ; + + +typedef void * opj_stream_t; + /* ========================================================== image typedef definitions @@ -525,15 +556,15 @@ Defines image data and characteristics */ typedef struct opj_image { /** XOsiz: horizontal offset from the origin of the reference grid to the left side of the image area */ - int x0; + OPJ_UINT32 x0; /** YOsiz: vertical offset from the origin of the reference grid to the top side of the image area */ - int y0; + OPJ_UINT32 y0; /** Xsiz: width of the reference grid */ - int x1; + OPJ_UINT32 x1; /** Ysiz: height of the reference grid */ - int y1; + OPJ_UINT32 y1; /** number of components in the image */ - int numcomps; + OPJ_UINT16 numcomps; /** color space: sRGB, Greyscale or YUV */ OPJ_COLOR_SPACE color_space; /** image components */ @@ -544,6 +575,7 @@ typedef struct opj_image { int icc_profile_len; } opj_image_t; + /** Component parameters structure used by the opj_image_create function */ @@ -783,6 +815,73 @@ Set position in byte stream */ OPJ_API void OPJ_CALLCONV cio_seek(opj_cio_t *cio, int pos); + +/** + * Creates an abstract stream. This function does nothing except allocating memory and initializing the abstract stream. + * + * @param l_is_reader if set to true then the stream will be an input stream, an output stream else. + * + * @return a stream object. +*/ +OPJ_API opj_stream_t* OPJ_CALLCONV opj_stream_default_create(opj_bool p_is_input); +OPJ_API opj_stream_t* OPJ_CALLCONV opj_stream_create(OPJ_UINT32 p_size, opj_bool p_is_input); + +/** + * Destroys a stream created by opj_create_stream. This function does NOT close the abstract stream. If needed the user must + * close its own implementation of the stream. + * + * @param p_stream the stream to destroy. + */ +OPJ_API void OPJ_CALLCONV opj_stream_destroy(opj_stream_t* p_stream); + +/** + * Sets the given function to be used as a read function. + * @param p_stream the stream to modify + * @param p_function the function to use a read function. +*/ +OPJ_API void OPJ_CALLCONV opj_stream_set_read_function(opj_stream_t* p_stream, opj_stream_read_fn p_function); + +/** + * Sets the given function to be used as a write function. + * @param p_stream the stream to modify + * @param p_function the function to use a write function. +*/ +OPJ_API void OPJ_CALLCONV opj_stream_set_write_function(opj_stream_t* p_stream, opj_stream_write_fn p_function); + +/** + * Sets the given function to be used as a skip function. + * @param p_stream the stream to modify + * @param p_function the function to use a skip function. +*/ +OPJ_API void OPJ_CALLCONV opj_stream_set_skip_function(opj_stream_t* p_stream, opj_stream_skip_fn p_function); + +/** + * Sets the given function to be used as a seek function, the stream is then seekable. + * @param p_stream the stream to modify + * @param p_function the function to use a skip function. +*/ +OPJ_API void OPJ_CALLCONV opj_stream_set_seek_function(opj_stream_t* p_stream, opj_stream_seek_fn p_function); + + +/** + * Sets the given data to be used as a user data for the stream. + * @param p_stream the stream to modify + * @param p_data the data to set. +*/ +OPJ_API void OPJ_CALLCONV opj_stream_set_user_data (opj_stream_t* p_stream, void * p_data); + + +/** + * Helper function. + * Sets the stream to be a file stream. The FILE must have been open previously. + * @param p_stream the stream to modify + * @param p_file handler to an already open file. +*/ +OPJ_API opj_stream_t* OPJ_CALLCONV opj_stream_create_default_file_stream (FILE * p_file, opj_bool p_is_read_stream); +OPJ_API opj_stream_t* OPJ_CALLCONV opj_stream_create_file_stream (FILE * p_file, OPJ_UINT32 p_buffer_size, opj_bool p_is_read_stream); + + + /* ========================================================== event manager functions definitions @@ -796,6 +895,14 @@ OPJ_API opj_event_mgr_t* OPJ_CALLCONV opj_set_event_mgr(opj_common_ptr cinfo, op codec functions definitions ========================================================== */ +/** +Creates a J2K/JPT/JP2 decompression structure +@param format Decoder to select +@return Returns a handle to a decompressor if successful, returns NULL otherwise +*/ +OPJ_API opj_codec_t* OPJ_CALLCONV opj_create_decompress_v2(OPJ_CODEC_FORMAT format); + + /** Creates a J2K/JPT/JP2 decompression structure @param format Decoder to select @@ -819,6 +926,11 @@ Decoding parameters are returned in j2k->cp. @param parameters decompression parameters */ OPJ_API void OPJ_CALLCONV opj_setup_decoder(opj_dinfo_t *dinfo, opj_dparameters_t *parameters); + +OPJ_API opj_bool OPJ_CALLCONV opj_setup_decoder_v2( opj_codec_t *p_info, + opj_dparameters_t *parameters, + opj_event_mgr_t* event_mgr); + /** Decode an image from a JPEG-2000 codestream @param dinfo decompressor handle @@ -900,6 +1012,35 @@ Destroy Codestream information after compression or decompression OPJ_API void OPJ_CALLCONV opj_destroy_cstr_info(opj_codestream_info_t *cstr_info); +/** + * Decodes an image header. + * + * @param p_codec codec to use to decode the image. + * @param p_image pointer to a previously created image. + * @param p_tile_x0 pointer to a value that will hold the reference point x0 of the tiling grid. + * @param p_tile_y0 pointer to a value that will hold the reference point y0 of the tiling grid. + * @param p_tile_width pointer to a value that will hold the size in x of a tile in the grid. + * @param p_tile_height pointer to a value that will hold the size in y of a tile in the grid. + * @param p_nb_tiles_x pointer to a value that will hold the number of tiles in the x direction. + * @param p_nb_tiles_y pointer to a value that will hold the number of tiles in the y direction. + */ +OPJ_API opj_bool OPJ_CALLCONV opj_read_header ( + opj_codec_t *p_codec, + opj_image_t ** p_image, + OPJ_INT32 * p_tile_x0, + OPJ_INT32 * p_tile_y0, + OPJ_UINT32 * p_tile_width, + OPJ_UINT32 * p_tile_height, + OPJ_UINT32 * p_nb_tiles_x, + OPJ_UINT32 * p_nb_tiles_y, + opj_stream_t *p_cio); + +/** +Destroy a decompressor handle +@param dinfo decompressor handle to destroy +*/ +OPJ_API void OPJ_CALLCONV opj_destroy_codec(opj_codec_t * p_codec); + #ifdef __cplusplus } #endif diff --git a/libopenjpeg/opj_includes.h b/libopenjpeg/opj_includes.h index 7bb79380..b5884dcf 100644 --- a/libopenjpeg/opj_includes.h +++ b/libopenjpeg/opj_includes.h @@ -40,6 +40,7 @@ #include #include #include +#include /* ========================================================== @@ -136,4 +137,7 @@ static INLINE long lrintf(float f){ #endif /* USE_JPWL */ /* <tw * p_cp->th); + + // initializations + l_tcp = &p_cp->tcps[p_tile_no]; + l_bound = l_tcp->numpocs+1; + + l_data_stride = 4 * J2K_MAXRLVLS; + l_tmp_data = (OPJ_UINT32*)opj_malloc( + l_data_stride * p_image->numcomps * sizeof(OPJ_UINT32)); + if + (! l_tmp_data) + { + return 00; + } + l_tmp_ptr = (OPJ_UINT32**)opj_malloc( + p_image->numcomps * sizeof(OPJ_UINT32 *)); + if + (! l_tmp_ptr) + { + opj_free(l_tmp_data); + return 00; + } + + // memory allocation for pi + l_pi = pi_create(p_image,p_cp,p_tile_no); + if + (!l_pi) + { + opj_free(l_tmp_data); + opj_free(l_tmp_ptr); + return 00; + } + + l_encoding_value_ptr = l_tmp_data; + // update pointer array + for + (compno = 0; compno < p_image->numcomps; ++compno) + { + l_tmp_ptr[compno] = l_encoding_value_ptr; + l_encoding_value_ptr += l_data_stride; + } + // get encoding parameters + get_all_encoding_parameters(p_image,p_cp,p_tile_no,&l_tx0,&l_tx1,&l_ty0,&l_ty1,&l_dx_min,&l_dy_min,&l_max_prec,&l_max_res,l_tmp_ptr); + + // step calculations + l_step_p = 1; + l_step_c = l_max_prec * l_step_p; + l_step_r = p_image->numcomps * l_step_c; + l_step_l = l_max_res * l_step_r; + + // set values for first packet iterator + l_current_pi = l_pi; + + // memory allocation for include + l_current_pi->include = (OPJ_INT16*) opj_calloc(l_tcp->numlayers * l_step_l, sizeof(OPJ_INT16)); + if + (!l_current_pi->include) + { + opj_free(l_tmp_data); + opj_free(l_tmp_ptr); + pi_destroy_v2(l_pi, l_bound); + return 00; + } + memset(l_current_pi->include,0,l_tcp->numlayers * l_step_l* sizeof(OPJ_INT16)); + + // special treatment for the first packet iterator + l_current_comp = l_current_pi->comps; + l_img_comp = p_image->comps; + l_tccp = l_tcp->tccps; + + l_current_pi->tx0 = l_tx0; + l_current_pi->ty0 = l_ty0; + l_current_pi->tx1 = l_tx1; + l_current_pi->ty1 = l_ty1; + + //l_current_pi->dx = l_img_comp->dx; + //l_current_pi->dy = l_img_comp->dy; + + l_current_pi->step_p = l_step_p; + l_current_pi->step_c = l_step_c; + l_current_pi->step_r = l_step_r; + l_current_pi->step_l = l_step_l; + + /* allocation for components and number of components has already been calculated by pi_create */ + for + (compno = 0; compno < l_current_pi->numcomps; ++compno) + { + opj_pi_resolution_t *l_res = l_current_comp->resolutions; + l_encoding_value_ptr = l_tmp_ptr[compno]; + + l_current_comp->dx = l_img_comp->dx; + l_current_comp->dy = l_img_comp->dy; + /* resolutions have already been initialized */ + for + (resno = 0; resno < l_current_comp->numresolutions; resno++) + { + l_res->pdx = *(l_encoding_value_ptr++); + l_res->pdy = *(l_encoding_value_ptr++); + l_res->pw = *(l_encoding_value_ptr++); + l_res->ph = *(l_encoding_value_ptr++); + ++l_res; + } + ++l_current_comp; + ++l_img_comp; + ++l_tccp; + } + ++l_current_pi; + + for + (pino = 1 ; pinocomps; + opj_image_comp_t * l_img_comp = p_image->comps; + l_tccp = l_tcp->tccps; + + l_current_pi->tx0 = l_tx0; + l_current_pi->ty0 = l_ty0; + l_current_pi->tx1 = l_tx1; + l_current_pi->ty1 = l_ty1; + //l_current_pi->dx = l_dx_min; + //l_current_pi->dy = l_dy_min; + l_current_pi->step_p = l_step_p; + l_current_pi->step_c = l_step_c; + l_current_pi->step_r = l_step_r; + l_current_pi->step_l = l_step_l; + + /* allocation for components and number of components has already been calculated by pi_create */ + for + (compno = 0; compno < l_current_pi->numcomps; ++compno) + { + opj_pi_resolution_t *l_res = l_current_comp->resolutions; + l_encoding_value_ptr = l_tmp_ptr[compno]; + + l_current_comp->dx = l_img_comp->dx; + l_current_comp->dy = l_img_comp->dy; + /* resolutions have already been initialized */ + for + (resno = 0; resno < l_current_comp->numresolutions; resno++) + { + l_res->pdx = *(l_encoding_value_ptr++); + l_res->pdy = *(l_encoding_value_ptr++); + l_res->pw = *(l_encoding_value_ptr++); + l_res->ph = *(l_encoding_value_ptr++); + ++l_res; + } + ++l_current_comp; + ++l_img_comp; + ++l_tccp; + } + // special treatment + l_current_pi->include = (l_current_pi-1)->include; + ++l_current_pi; + } + opj_free(l_tmp_data); + l_tmp_data = 00; + opj_free(l_tmp_ptr); + l_tmp_ptr = 00; + if + (l_tcp->POC) + { + pi_update_decode_poc (l_pi,l_tcp,l_max_prec,l_max_res); + } + else + { + pi_update_decode_not_poc(l_pi,l_tcp,l_max_prec,l_max_res); + } + return l_pi; +} + opj_pi_iterator_t *pi_initialise_encode(opj_image_t *image, opj_cp_t *cp, int tileno, J2K_T2_MODE t2_mode){ int p, q, pino; int compno, resno; @@ -961,3 +1221,355 @@ opj_bool pi_create_encode( opj_pi_iterator_t *pi, opj_cp_t *cp,int tileno, int p return OPJ_FALSE; } + + +/** + * Gets the encoding parameters needed to update the coding parameters and all the pocs. + * The precinct widths, heights, dx and dy for each component at each resolution will be stored as well. + * the last parameter of the function should be an array of pointers of size nb components, each pointer leading + * to an area of size 4 * max_res. The data is stored inside this area with the following pattern : + * dx_compi_res0 , dy_compi_res0 , w_compi_res0, h_compi_res0 , dx_compi_res1 , dy_compi_res1 , w_compi_res1, h_compi_res1 , ... + * + * @param p_image the image being encoded. + * @param p_cp the coding parameters. + * @param tileno the tile index of the tile being encoded. + * @param p_tx0 pointer that will hold the X0 parameter for the tile + * @param p_tx1 pointer that will hold the X1 parameter for the tile + * @param p_ty0 pointer that will hold the Y0 parameter for the tile + * @param p_ty1 pointer that will hold the Y1 parameter for the tile + * @param p_max_prec pointer that will hold the the maximum precision for all the bands of the tile + * @param p_max_res pointer that will hold the the maximum number of resolutions for all the poc inside the tile. + * @param dx_min pointer that will hold the the minimum dx of all the components of all the resolutions for the tile. + * @param dy_min pointer that will hold the the minimum dy of all the components of all the resolutions for the tile. + * @param p_resolutions pointer to an area corresponding to the one described above. + */ +void get_all_encoding_parameters( + const opj_image_t *p_image, + const opj_cp_v2_t *p_cp, + OPJ_UINT32 tileno, + OPJ_INT32 * p_tx0, + OPJ_INT32 * p_tx1, + OPJ_INT32 * p_ty0, + OPJ_INT32 * p_ty1, + OPJ_UINT32 * p_dx_min, + OPJ_UINT32 * p_dy_min, + OPJ_UINT32 * p_max_prec, + OPJ_UINT32 * p_max_res, + OPJ_UINT32 ** p_resolutions + ) +{ + // loop + OPJ_UINT32 compno, resno; + + // pointers + const opj_tcp_v2_t *tcp = 00; + const opj_tccp_t * l_tccp = 00; + const opj_image_comp_t * l_img_comp = 00; + + // to store l_dx, l_dy, w and h for each resolution and component. + OPJ_UINT32 * lResolutionPtr; + + // position in x and y of tile + OPJ_UINT32 p, q; + + // preconditions in debug + assert(p_cp != 00); + assert(p_image != 00); + assert(tileno < p_cp->tw * p_cp->th); + + // initializations + tcp = &p_cp->tcps [tileno]; + l_tccp = tcp->tccps; + l_img_comp = p_image->comps; + + // position in x and y of tile + + p = tileno % p_cp->tw; + q = tileno / p_cp->tw; + + /* here calculation of tx0, tx1, ty0, ty1, maxprec, l_dx and l_dy */ + *p_tx0 = int_max(p_cp->tx0 + p * p_cp->tdx, p_image->x0); + *p_tx1 = int_min(p_cp->tx0 + (p + 1) * p_cp->tdx, p_image->x1); + *p_ty0 = int_max(p_cp->ty0 + q * p_cp->tdy, p_image->y0); + *p_ty1 = int_min(p_cp->ty0 + (q + 1) * p_cp->tdy, p_image->y1); + + // max precision and resolution is 0 (can only grow) + *p_max_prec = 0; + *p_max_res = 0; + + // take the largest value for dx_min and dy_min + *p_dx_min = 0x7fffffff; + *p_dy_min = 0x7fffffff; + + for + (compno = 0; compno < p_image->numcomps; ++compno) + { + // aritmetic variables to calculate + OPJ_UINT32 l_level_no; + OPJ_INT32 l_rx0, l_ry0, l_rx1, l_ry1; + OPJ_INT32 l_px0, l_py0, l_px1, py1; + OPJ_UINT32 l_product; + OPJ_INT32 l_tcx0, l_tcy0, l_tcx1, l_tcy1; + OPJ_UINT32 l_pdx, l_pdy , l_pw , l_ph; + + lResolutionPtr = p_resolutions[compno]; + + l_tcx0 = int_ceildiv(*p_tx0, l_img_comp->dx); + l_tcy0 = int_ceildiv(*p_ty0, l_img_comp->dy); + l_tcx1 = int_ceildiv(*p_tx1, l_img_comp->dx); + l_tcy1 = int_ceildiv(*p_ty1, l_img_comp->dy); + if + (l_tccp->numresolutions > *p_max_res) + { + *p_max_res = l_tccp->numresolutions; + } + + // use custom size for precincts + l_level_no = l_tccp->numresolutions - 1; + for + (resno = 0; resno < l_tccp->numresolutions; ++resno) + { + OPJ_UINT32 l_dx, l_dy; + // precinct width and height + l_pdx = l_tccp->prcw[resno]; + l_pdy = l_tccp->prch[resno]; + *lResolutionPtr++ = l_pdx; + *lResolutionPtr++ = l_pdy; + l_dx = l_img_comp->dx * (1 << (l_pdx + l_level_no)); + l_dy = l_img_comp->dy * (1 << (l_pdy + l_level_no)); + // take the minimum size for l_dx for each comp and resolution + *p_dx_min = int_min(*p_dx_min, l_dx); + *p_dy_min = int_min(*p_dy_min, l_dy); + // various calculations of extents + + l_rx0 = int_ceildivpow2(l_tcx0, l_level_no); + l_ry0 = int_ceildivpow2(l_tcy0, l_level_no); + l_rx1 = int_ceildivpow2(l_tcx1, l_level_no); + l_ry1 = int_ceildivpow2(l_tcy1, l_level_no); + l_px0 = int_floordivpow2(l_rx0, l_pdx) << l_pdx; + l_py0 = int_floordivpow2(l_ry0, l_pdy) << l_pdy; + l_px1 = int_ceildivpow2(l_rx1, l_pdx) << l_pdx; + py1 = int_ceildivpow2(l_ry1, l_pdy) << l_pdy; + l_pw = (l_rx0==l_rx1)?0:((l_px1 - l_px0) >> l_pdx); + l_ph = (l_ry0==l_ry1)?0:((py1 - l_py0) >> l_pdy); + *lResolutionPtr++ = l_pw; + *lResolutionPtr++ = l_ph; + l_product = l_pw * l_ph; + // update precision + if + (l_product > *p_max_prec) + { + *p_max_prec = l_product; + } + --l_level_no; + } + ++l_tccp; + ++l_img_comp; + } +} + +/** + * Allocates memory for a packet iterator. Data and data sizes are set by this operation. + * No other data is set. The include section of the packet iterator is not allocated. + * + * @param p_image the image used to initialize the packet iterator (in fact only the number of components is relevant. + * @param p_cp the coding parameters. + * @param p_tile_no the index of the tile from which creating the packet iterator. + */ +opj_pi_iterator_t * pi_create( + const opj_image_t *image, + const opj_cp_v2_t *cp, + OPJ_UINT32 tileno + ) +{ + // loop + OPJ_UINT32 pino, compno; + // number of poc in the p_pi + OPJ_UINT32 l_poc_bound; + + // pointers to tile coding parameters and components. + opj_pi_iterator_t *l_pi = 00; + opj_tcp_v2_t *tcp = 00; + const opj_tccp_t *tccp = 00; + + // current packet iterator being allocated + opj_pi_iterator_t *l_current_pi = 00; + + // preconditions in debug + assert(cp != 00); + assert(image != 00); + assert(tileno < cp->tw * cp->th); + + // initializations + tcp = &cp->tcps[tileno]; + l_poc_bound = tcp->numpocs+1; + + + // memory allocations + l_pi = (opj_pi_iterator_t*) opj_calloc((l_poc_bound), sizeof(opj_pi_iterator_t)); + + if + (!l_pi) + { + return 00; + } + memset(l_pi,0,l_poc_bound * sizeof(opj_pi_iterator_t)); + l_current_pi = l_pi; + for + (pino = 0; pino < l_poc_bound ; ++pino) + { + l_current_pi->comps = (opj_pi_comp_t*) opj_calloc(image->numcomps, sizeof(opj_pi_comp_t)); + if + (! l_current_pi->comps) + { + pi_destroy_v2(l_pi, l_poc_bound); + return 00; + } + l_current_pi->numcomps = image->numcomps; + memset(l_current_pi->comps,0,image->numcomps * sizeof(opj_pi_comp_t)); + for + (compno = 0; compno < image->numcomps; ++compno) + { + opj_pi_comp_t *comp = &l_current_pi->comps[compno]; + tccp = &tcp->tccps[compno]; + comp->resolutions = (opj_pi_resolution_t*) opj_malloc(tccp->numresolutions * sizeof(opj_pi_resolution_t)); + if + (!comp->resolutions) + { + pi_destroy_v2(l_pi, l_poc_bound); + return 00; + } + comp->numresolutions = tccp->numresolutions; + memset(comp->resolutions,0,tccp->numresolutions * sizeof(opj_pi_resolution_t)); + } + ++l_current_pi; + } + return l_pi; +} + + + +/** + * Destroys a packet iterator array. + * + * @param p_pi the packet iterator array to destroy. + * @param p_nb_elements the number of elements in the array. + */ +void pi_destroy_v2( + opj_pi_iterator_t *p_pi, + OPJ_UINT32 p_nb_elements) +{ + OPJ_UINT32 compno, pino; + opj_pi_iterator_t *l_current_pi = p_pi; + if + (p_pi) + { + if + (p_pi->include) + { + opj_free(p_pi->include); + p_pi->include = 00; + } + // TODO + for + (pino = 0; pino < p_nb_elements; ++pino) + { + if + (l_current_pi->comps) + { + opj_pi_comp_t *l_current_component = l_current_pi->comps; + for + (compno = 0; compno < l_current_pi->numcomps; compno++) + { + if + (l_current_component->resolutions) + { + opj_free(l_current_component->resolutions); + l_current_component->resolutions = 00; + } + ++l_current_component; + } + opj_free(l_current_pi->comps); + l_current_pi->comps = 0; + } + ++l_current_pi; + } + opj_free(p_pi); + } +} + + + +void pi_update_decode_poc (opj_pi_iterator_t * p_pi,opj_tcp_v2_t * p_tcp,OPJ_UINT32 p_max_precision,OPJ_UINT32 p_max_res) +{ + // loop + OPJ_UINT32 pino; + + // encoding prameters to set + OPJ_UINT32 l_bound; + + opj_pi_iterator_t * l_current_pi = 00; + opj_poc_t* l_current_poc = 0; + + // preconditions in debug + assert(p_pi != 00); + assert(p_tcp != 00); + + // initializations + l_bound = p_tcp->numpocs+1; + l_current_pi = p_pi; + l_current_poc = p_tcp->pocs; + + for + (pino = 0;pinopoc.prg = l_current_poc->prg; + l_current_pi->first = 1; + + l_current_pi->poc.resno0 = l_current_poc->resno0; + l_current_pi->poc.compno0 = l_current_poc->compno0; + l_current_pi->poc.layno0 = 0; + l_current_pi->poc.precno0 = 0; + l_current_pi->poc.resno1 = l_current_poc->resno1; + l_current_pi->poc.compno1 = l_current_poc->compno1; + l_current_pi->poc.layno1 = l_current_poc->layno1; + l_current_pi->poc.precno1 = p_max_precision; + ++l_current_pi; + ++l_current_poc; + } +} + + +void pi_update_decode_not_poc (opj_pi_iterator_t * p_pi,opj_tcp_v2_t * p_tcp,OPJ_UINT32 p_max_precision,OPJ_UINT32 p_max_res) +{ + // loop + OPJ_UINT32 pino; + + // encoding prameters to set + OPJ_UINT32 l_bound; + + opj_pi_iterator_t * l_current_pi = 00; + // preconditions in debug + assert(p_tcp != 00); + assert(p_pi != 00); + + // initializations + l_bound = p_tcp->numpocs+1; + l_current_pi = p_pi; + + for + (pino = 0;pinopoc.prg = p_tcp->prg; + l_current_pi->first = 1; + l_current_pi->poc.resno0 = 0; + l_current_pi->poc.compno0 = 0; + l_current_pi->poc.layno0 = 0; + l_current_pi->poc.precno0 = 0; + l_current_pi->poc.resno1 = p_max_res; + l_current_pi->poc.compno1 = l_current_pi->numcomps; + l_current_pi->poc.layno1 = p_tcp->numlayers; + l_current_pi->poc.precno1 = p_max_precision; + ++l_current_pi; + } +} diff --git a/libopenjpeg/pi.h b/libopenjpeg/pi.h index cf9135fd..5c7b9981 100644 --- a/libopenjpeg/pi.h +++ b/libopenjpeg/pi.h @@ -133,6 +133,18 @@ Create a packet iterator for Decoder */ opj_pi_iterator_t *pi_create_decode(opj_image_t * image, opj_cp_t * cp, int tileno); + +/** +Create a packet iterator for Decoder +@param image Raw image for which the packets will be listed +@param cp Coding parameters +@param tileno Number that identifies the tile for which to list the packets +@return Returns a packet iterator that points to the first packet of the tile +@see pi_destroy +*/ +opj_pi_iterator_t *pi_create_decode_v2(struct opj_image * image, struct opj_cp_v2 * cp, OPJ_UINT32 tileno); + + /** Destroy a packet iterator @param pi Previously created packet iterator @@ -142,6 +154,17 @@ Destroy a packet iterator */ void pi_destroy(opj_pi_iterator_t *pi, opj_cp_t *cp, int tileno); + +/** + * Destroys a packet iterator array. + * + * @param p_pi the packet iterator array to destroy. + * @param p_nb_elements the number of elements in the array. + */ +void pi_destroy_v2( + opj_pi_iterator_t *p_pi, + OPJ_UINT32 p_nb_elements); + /** Modify the packet iterator to point to the next packet @param pi Packet iterator to modify diff --git a/libopenjpeg/t1.c b/libopenjpeg/t1.c index b3ede36a..a5b102cb 100644 --- a/libopenjpeg/t1.c +++ b/libopenjpeg/t1.c @@ -1582,3 +1582,74 @@ void t1_decode_cblks( } /* resno */ } + + +/* ----------------------------------------------------------------------- */ +/** + * Creates a new Tier 1 handle + * and initializes the look-up tables of the Tier-1 coder/decoder + * @return a new T1 handle if successful, returns NULL otherwise +*/ +opj_t1_t* t1_create_v2() +{ + opj_t1_t *l_t1 = 00; + + l_t1 = (opj_t1_t*) opj_malloc(sizeof(opj_t1_t)); + if + (!l_t1) + { + return 00; + } + memset(l_t1,0,sizeof(opj_t1_t)); + + /* create MQC and RAW handles */ + l_t1->mqc = mqc_create(); + if + (! l_t1->mqc) + { + t1_destroy(l_t1); + return 00; + } + l_t1->raw = raw_create(); + if + (! l_t1->raw) + { + t1_destroy(l_t1); + return 00; + } + return l_t1; +} + + +/** + * Destroys a previously created T1 handle + * + * @param p_t1 Tier 1 handle to destroy +*/ +void t1_destroy_v2(opj_t1_t *p_t1) +{ + if + (! p_t1) + { + return; + } + + /* destroy MQC and RAW handles */ + mqc_destroy(p_t1->mqc); + p_t1->mqc = 00; + raw_destroy(p_t1->raw); + p_t1->raw = 00; + if + (p_t1->data) + { + opj_aligned_free(p_t1->data); + p_t1->data = 00; + } + if + (p_t1->flags) + { + opj_aligned_free(p_t1->flags); + p_t1->flags = 00; + } + opj_free(p_t1); +} diff --git a/libopenjpeg/t1.h b/libopenjpeg/t1.h index 572ec88d..bcc6e514 100644 --- a/libopenjpeg/t1.h +++ b/libopenjpeg/t1.h @@ -139,6 +139,22 @@ Decode the code-blocks of a tile @param tccp Tile coding parameters */ void t1_decode_cblks(opj_t1_t* t1, opj_tcd_tilecomp_t* tilec, opj_tccp_t* tccp); + + + +/** + * Creates a new Tier 1 handle + * and initializes the look-up tables of the Tier-1 coder/decoder + * @return a new T1 handle if successful, returns NULL otherwise +*/ +opj_t1_t* t1_create_v2(); + +/** + * Destroys a previously created T1 handle + * + * @param p_t1 Tier 1 handle to destroy +*/ +void t1_destroy_v2(opj_t1_t *p_t1); /* ----------------------------------------------------------------------- */ /*@}*/ diff --git a/libopenjpeg/t2.c b/libopenjpeg/t2.c index 76821afc..93a296b7 100644 --- a/libopenjpeg/t2.c +++ b/libopenjpeg/t2.c @@ -79,6 +79,72 @@ Decode a packet of a tile from a source buffer static int t2_decode_packet(opj_t2_t* t2, unsigned char *src, int len, opj_tcd_tile_t *tile, opj_tcp_t *tcp, opj_pi_iterator_t *pi, opj_packet_info_t *pack_info); + +/** +Decode a packet of a tile from a source buffer +@param t2 T2 handle +@param src Source buffer +@param len Length of the source buffer +@param tile Tile for which to write the packets +@param tcp Tile coding parameters +@param pi Packet identity +@return +*/ +static opj_bool t2_decode_packet_v2( + opj_t2_v2_t* p_t2, + opj_tcd_tile_t *p_tile, + opj_tcp_v2_t *p_tcp, + opj_pi_iterator_t *p_pi, + OPJ_BYTE *p_src, + OPJ_UINT32 * p_data_read, + OPJ_UINT32 p_max_length, + opj_packet_info_t *p_pack_info); + +static opj_bool t2_skip_packet( + opj_t2_v2_t* p_t2, + opj_tcd_tile_t *p_tile, + opj_tcp_v2_t *p_tcp, + opj_pi_iterator_t *p_pi, + OPJ_BYTE *p_src, + OPJ_UINT32 * p_data_read, + OPJ_UINT32 p_max_length, + opj_packet_info_t *p_pack_info); + +static opj_bool t2_read_packet_header( + opj_t2_v2_t* p_t2, + opj_tcd_tile_t *p_tile, + opj_tcp_v2_t *p_tcp, + opj_pi_iterator_t *p_pi, + opj_bool * p_is_data_present, + OPJ_BYTE *p_src_data, + OPJ_UINT32 * p_data_read, + OPJ_UINT32 p_max_length, + opj_packet_info_t *p_pack_info); + +static opj_bool t2_read_packet_data( + opj_t2_v2_t* p_t2, + opj_tcd_tile_t *p_tile, + opj_pi_iterator_t *p_pi, + OPJ_BYTE *p_src_data, + OPJ_UINT32 * p_data_read, + OPJ_UINT32 p_max_length, + opj_packet_info_t *pack_info); + +static opj_bool t2_skip_packet_data( + opj_t2_v2_t* p_t2, + opj_tcd_tile_t *p_tile, + opj_pi_iterator_t *p_pi, + OPJ_UINT32 * p_data_read, + OPJ_UINT32 p_max_length, + opj_packet_info_t *pack_info); + +/** +@param seg +@param cblksty +@param first +*/ +static opj_bool t2_init_seg_v2(opj_tcd_cblk_dec_t* cblk, OPJ_UINT32 index, OPJ_UINT32 cblksty, OPJ_UINT32 first); + /*@}*/ /*@}*/ @@ -768,6 +834,116 @@ int t2_decode_packets(opj_t2_t *t2, unsigned char *src, int len, int tileno, opj return (c - src); } +opj_bool t2_decode_packets_v2( + opj_t2_v2_t *p_t2, + OPJ_UINT32 p_tile_no, + struct opj_tcd_tile *p_tile, + OPJ_BYTE *p_src, + OPJ_UINT32 * p_data_read, + OPJ_UINT32 p_max_len, + struct opj_codestream_info *p_cstr_info) +{ + OPJ_BYTE *l_current_data = p_src; + opj_pi_iterator_t *l_pi = 00; + OPJ_UINT32 pino; + opj_image_t *l_image = p_t2->image; + opj_cp_v2_t *l_cp = p_t2->cp; + opj_cp_v2_t *cp = p_t2->cp; + opj_tcp_v2_t *l_tcp = &(p_t2->cp->tcps[p_tile_no]); + OPJ_UINT32 l_nb_bytes_read; + OPJ_UINT32 l_nb_pocs = l_tcp->numpocs + 1; + opj_pi_iterator_t *l_current_pi = 00; + OPJ_UINT32 curtp = 0; + OPJ_UINT32 tp_start_packno; + opj_packet_info_t *l_pack_info = 00; + opj_image_comp_t* l_img_comp = 00; + + + if + (p_cstr_info) + { + l_pack_info = p_cstr_info->tile[p_tile_no].packet; + } + + /* create a packet iterator */ + l_pi = pi_create_decode_v2(l_image, l_cp, p_tile_no); + if + (!l_pi) + { + return OPJ_FALSE; + } + + tp_start_packno = 0; + l_current_pi = l_pi; + + for + (pino = 0; pino <= l_tcp->numpocs; ++pino) + { + while + (pi_next(l_current_pi)) + { + + if + (l_tcp->num_layers_to_decode > l_current_pi->layno && l_current_pi->resno < p_tile->comps[l_current_pi->compno].minimum_num_resolutions) + { + l_nb_bytes_read = 0; + if + (! t2_decode_packet_v2(p_t2,p_tile,l_tcp,l_current_pi,l_current_data,&l_nb_bytes_read,p_max_len,l_pack_info)) + { + pi_destroy_v2(l_pi,l_nb_pocs); + return OPJ_FALSE; + } + l_img_comp = &(l_image->comps[l_current_pi->compno]); + l_img_comp->resno_decoded = uint_max(l_current_pi->resno, l_img_comp->resno_decoded); + } + else + { + l_nb_bytes_read = 0; + if + (! t2_skip_packet(p_t2,p_tile,l_tcp,l_current_pi,l_current_data,&l_nb_bytes_read,p_max_len,l_pack_info)) + { + pi_destroy_v2(l_pi,l_nb_pocs); + return OPJ_FALSE; + } + } + l_current_data += l_nb_bytes_read; + p_max_len -= l_nb_bytes_read; + + /* INDEX >> */ + if(p_cstr_info) { + opj_tile_info_t *info_TL = &p_cstr_info->tile[p_tile_no]; + opj_packet_info_t *info_PK = &info_TL->packet[p_cstr_info->packno]; + if (!p_cstr_info->packno) { + info_PK->start_pos = info_TL->end_header + 1; + } else if (info_TL->packet[p_cstr_info->packno-1].end_pos >= (OPJ_INT32)p_cstr_info->tile[p_tile_no].tp[curtp].tp_end_pos){ // New tile part + info_TL->tp[curtp].tp_numpacks = p_cstr_info->packno - tp_start_packno; // Number of packets in previous tile-part + tp_start_packno = p_cstr_info->packno; + curtp++; + info_PK->start_pos = p_cstr_info->tile[p_tile_no].tp[curtp].tp_end_header+1; + } else { + info_PK->start_pos = (cp->m_specific_param.m_enc.m_tp_on && info_PK->start_pos) ? info_PK->start_pos : info_TL->packet[p_cstr_info->packno - 1].end_pos + 1; + } + info_PK->end_pos = info_PK->start_pos + l_nb_bytes_read - 1; + info_PK->end_ph_pos += info_PK->start_pos - 1; // End of packet header which now only represents the distance + ++p_cstr_info->packno; + } + /* << INDEX */ + } + ++l_current_pi; + } + /* INDEX >> */ + if + (p_cstr_info) { + p_cstr_info->tile[p_tile_no].tp[curtp].tp_numpacks = p_cstr_info->packno - tp_start_packno; // Number of packets in last tile-part + } + /* << INDEX */ + + /* don't forget to release pi */ + pi_destroy_v2(l_pi,l_nb_pocs); + *p_data_read = l_current_data - p_src; + return OPJ_TRUE; +} + /* ----------------------------------------------------------------------- */ opj_t2_t* t2_create(opj_common_ptr cinfo, opj_image_t *image, opj_cp_t *cp) { @@ -781,13 +957,660 @@ opj_t2_t* t2_create(opj_common_ptr cinfo, opj_image_t *image, opj_cp_t *cp) { return t2; } +/** + * Creates a Tier 2 handle + * + * @param p_image Source or destination image + * @param p_cp Image coding parameters. + * @return a new T2 handle if successful, NULL otherwise. +*/ +opj_t2_v2_t* t2_create_v2( + opj_image_t *p_image, + opj_cp_v2_t *p_cp) +{ + /* create the tcd structure */ + opj_t2_v2_t *l_t2 = (opj_t2_v2_t*)opj_malloc(sizeof(opj_t2_v2_t)); + if + (!l_t2) + { + return 00; + } + memset(l_t2,0,sizeof(opj_t2_t)); + l_t2->image = p_image; + l_t2->cp = p_cp; + return l_t2; +} + void t2_destroy(opj_t2_t *t2) { if(t2) { opj_free(t2); } } +void t2_destroy_v2(opj_t2_v2_t *t2) { + if(t2) { + opj_free(t2); + } +} + + +static opj_bool t2_decode_packet_v2( + opj_t2_v2_t* p_t2, + opj_tcd_tile_t *p_tile, + opj_tcp_v2_t *p_tcp, + opj_pi_iterator_t *p_pi, + OPJ_BYTE *p_src, + OPJ_UINT32 * p_data_read, + OPJ_UINT32 p_max_length, + opj_packet_info_t *p_pack_info) +{ + opj_bool l_read_data; + OPJ_UINT32 l_nb_bytes_read = 0; + OPJ_UINT32 l_nb_total_bytes_read = 0; + + *p_data_read = 0; + + if + (! t2_read_packet_header(p_t2,p_tile,p_tcp,p_pi,&l_read_data,p_src,&l_nb_bytes_read,p_max_length,p_pack_info)) + { + return OPJ_FALSE; + } + p_src += l_nb_bytes_read; + l_nb_total_bytes_read += l_nb_bytes_read; + p_max_length -= l_nb_bytes_read; + /* we should read data for the packet */ + if + (l_read_data) + { + l_nb_bytes_read = 0; + if + (! t2_read_packet_data(p_t2,p_tile,p_pi,p_src,&l_nb_bytes_read,p_max_length,p_pack_info)) + { + return OPJ_FALSE; + } + l_nb_total_bytes_read += l_nb_bytes_read; + } + *p_data_read = l_nb_total_bytes_read; + return OPJ_FALSE; +} + +static opj_bool t2_skip_packet( + opj_t2_v2_t* p_t2, + opj_tcd_tile_t *p_tile, + opj_tcp_v2_t *p_tcp, + opj_pi_iterator_t *p_pi, + OPJ_BYTE *p_src, + OPJ_UINT32 * p_data_read, + OPJ_UINT32 p_max_length, + opj_packet_info_t *p_pack_info) +{ + opj_bool l_read_data; + OPJ_UINT32 l_nb_bytes_read = 0; + OPJ_UINT32 l_nb_total_bytes_read = 0; + + *p_data_read = 0; + + if + (! t2_read_packet_header(p_t2,p_tile,p_tcp,p_pi,&l_read_data,p_src,&l_nb_bytes_read,p_max_length,p_pack_info)) + { + return OPJ_FALSE; + } + p_src += l_nb_bytes_read; + l_nb_total_bytes_read += l_nb_bytes_read; + p_max_length -= l_nb_bytes_read; + /* we should read data for the packet */ + if + (l_read_data) + { + l_nb_bytes_read = 0; + if + (! t2_skip_packet_data(p_t2,p_tile,p_pi,&l_nb_bytes_read,p_max_length,p_pack_info)) + { + return OPJ_FALSE; + } + l_nb_total_bytes_read += l_nb_bytes_read; + } + *p_data_read = l_nb_total_bytes_read; + return OPJ_TRUE; +} +static opj_bool t2_read_packet_header( + opj_t2_v2_t* p_t2, + opj_tcd_tile_t *p_tile, + opj_tcp_v2_t *p_tcp, + opj_pi_iterator_t *p_pi, + opj_bool * p_is_data_present, + OPJ_BYTE *p_src_data, + OPJ_UINT32 * p_data_read, + OPJ_UINT32 p_max_length, + opj_packet_info_t *p_pack_info) +{ + /* loop */ + OPJ_UINT32 bandno, cblkno; + OPJ_UINT32 l_nb_code_blocks; + OPJ_UINT32 l_remaining_length; + OPJ_UINT32 l_header_length; + OPJ_UINT32 * l_modified_length_ptr = 00; + OPJ_BYTE *l_current_data = p_src_data; + opj_cp_v2_t *l_cp = p_t2->cp; + opj_bio_t *l_bio = 00; /* BIO component */ + opj_tcd_band_t *l_band = 00; + opj_tcd_cblk_dec_t* l_cblk = 00; + opj_tcd_resolution_t* l_res = &p_tile->comps[p_pi->compno].resolutions[p_pi->resno]; + OPJ_BYTE *l_header_data = 00; + OPJ_BYTE **l_header_data_start = 00; + + OPJ_UINT32 l_present; + + if + (p_pi->layno == 0) + { + l_band = l_res->bands; + /* reset tagtrees */ + for + (bandno = 0; bandno < l_res->numbands; ++bandno) + { + opj_tcd_precinct_t *l_prc = &l_band->precincts[p_pi->precno]; + + if ( + ! ((l_band->x1-l_band->x0 == 0)||(l_band->y1-l_band->y0 == 0))) + { + tgt_reset(l_prc->incltree); + tgt_reset(l_prc->imsbtree); + l_cblk = l_prc->cblks.dec; + l_nb_code_blocks = l_prc->cw * l_prc->ch; + for + (cblkno = 0; cblkno < l_nb_code_blocks; ++cblkno) + { + l_cblk->numsegs = 0; + l_cblk->real_num_segs = 0; + ++l_cblk; + } + } + ++l_band; + } + } + + /* SOP markers */ + + if (p_tcp->csty & J2K_CP_CSTY_SOP) { + if ((*l_current_data) != 0xff || (*(l_current_data + 1) != 0x91)) { + // TODO opj_event_msg(t2->cinfo->event_mgr, EVT_WARNING, "Expected SOP marker\n"); + } else { + l_current_data += 6; + } + + /** TODO : check the Nsop value */ + } + + /* + When the marker PPT/PPM is used the packet header are store in PPT/PPM marker + This part deal with this caracteristic + step 1: Read packet header in the saved structure + step 2: Return to codestream for decoding + */ + + l_bio = bio_create(); + if + (! l_bio) + { + return OPJ_FALSE; + } + + if + (l_cp->ppm == 1) + { /* PPM */ + l_header_data_start = &l_cp->ppm_data; + l_header_data = *l_header_data_start; + l_modified_length_ptr = &(l_cp->ppm_len); + + } + else if + (p_tcp->ppt == 1) + { /* PPT */ + l_header_data_start = &(p_tcp->ppt_data); + l_header_data = *l_header_data_start; + l_modified_length_ptr = &(p_tcp->ppt_len); + } + else + { /* Normal Case */ + l_header_data_start = &(l_current_data); + l_header_data = *l_header_data_start; + l_remaining_length = p_src_data+p_max_length-l_header_data; + l_modified_length_ptr = &(l_remaining_length); + } + bio_init_dec(l_bio, l_header_data,*l_modified_length_ptr); + l_present = bio_read(l_bio, 1); + if + (!l_present) + { + bio_inalign(l_bio); + l_header_data += bio_numbytes(l_bio); + bio_destroy(l_bio); + /* EPH markers */ + if (p_tcp->csty & J2K_CP_CSTY_EPH) { + if ((*l_header_data) != 0xff || (*(l_header_data + 1) != 0x92)) { + printf("Error : expected EPH marker\n"); + } else { + l_header_data += 2; + } + } + l_header_length = (l_header_data - *l_header_data_start); + *l_modified_length_ptr -= l_header_length; + *l_header_data_start += l_header_length; + /* << INDEX */ + // End of packet header position. Currently only represents the distance to start of packet + // Will be updated later by incrementing with packet start value + if + (p_pack_info) + { + p_pack_info->end_ph_pos = (OPJ_INT32)(l_current_data - p_src_data); + } + /* INDEX >> */ + * p_is_data_present = OPJ_FALSE; + *p_data_read = l_current_data - p_src_data; + return OPJ_TRUE; + } + + l_band = l_res->bands; + for + (bandno = 0; bandno < l_res->numbands; ++bandno) + { + opj_tcd_precinct_t *l_prc = &(l_band->precincts[p_pi->precno]); + + if ((l_band->x1-l_band->x0 == 0)||(l_band->y1-l_band->y0 == 0)) + { + ++l_band; + continue; + } + l_nb_code_blocks = l_prc->cw * l_prc->ch; + l_cblk = l_prc->cblks.dec; + for + (cblkno = 0; cblkno < l_nb_code_blocks; cblkno++) + { + OPJ_UINT32 l_included,l_increment, l_segno; + OPJ_INT32 n; + /* if cblk not yet included before --> inclusion tagtree */ + if + (!l_cblk->numsegs) + { + l_included = tgt_decode(l_bio, l_prc->incltree, cblkno, p_pi->layno + 1); + /* else one bit */ + } + else + { + l_included = bio_read(l_bio, 1); + } + /* if cblk not included */ + if + (!l_included) + { + l_cblk->numnewpasses = 0; + ++l_cblk; + continue; + } + /* if cblk not yet included --> zero-bitplane tagtree */ + if + (!l_cblk->numsegs) + { + OPJ_UINT32 i = 0; + while + (!tgt_decode(l_bio, l_prc->imsbtree, cblkno, i)) + { + ++i; + } + l_cblk->numbps = l_band->numbps + 1 - i; + l_cblk->numlenbits = 3; + } + /* number of coding passes */ + l_cblk->numnewpasses = t2_getnumpasses(l_bio); + l_increment = t2_getcommacode(l_bio); + /* length indicator increment */ + l_cblk->numlenbits += l_increment; + l_segno = 0; + if + (!l_cblk->numsegs) + { + if + (! t2_init_seg_v2(l_cblk, l_segno, p_tcp->tccps[p_pi->compno].cblksty, 1)) + { + bio_destroy(l_bio); + return OPJ_FALSE; + } + + } + else + { + l_segno = l_cblk->numsegs - 1; + if + (l_cblk->segs[l_segno].numpasses == l_cblk->segs[l_segno].maxpasses) + { + ++l_segno; + if + (! t2_init_seg_v2(l_cblk, l_segno, p_tcp->tccps[p_pi->compno].cblksty, 0)) + { + bio_destroy(l_bio); + return OPJ_FALSE; + } + } + } + n = l_cblk->numnewpasses; + + do { + l_cblk->segs[l_segno].numnewpasses = int_min(l_cblk->segs[l_segno].maxpasses - l_cblk->segs[l_segno].numpasses, n); + l_cblk->segs[l_segno].newlen = bio_read(l_bio, l_cblk->numlenbits + uint_floorlog2(l_cblk->segs[l_segno].numnewpasses)); + n -= l_cblk->segs[l_segno].numnewpasses; + if + (n > 0) + { + ++l_segno; + if + (! t2_init_seg_v2(l_cblk, l_segno, p_tcp->tccps[p_pi->compno].cblksty, 0)) + { + bio_destroy(l_bio); + return OPJ_FALSE; + } + } + } + while (n > 0); + ++l_cblk; + } + ++l_band; + } + + if + (bio_inalign(l_bio)) + { + bio_destroy(l_bio); + return OPJ_FALSE; + } + + l_header_data += bio_numbytes(l_bio); + bio_destroy(l_bio); + + /* EPH markers */ + if (p_tcp->csty & J2K_CP_CSTY_EPH) { + if ((*l_header_data) != 0xff || (*(l_header_data + 1) != 0x92)) { + // TODO opj_event_msg(t2->cinfo->event_mgr, EVT_ERROR, "Expected EPH marker\n"); + } else { + l_header_data += 2; + } + } + + + l_header_length = (l_header_data - *l_header_data_start); + *l_modified_length_ptr -= l_header_length; + *l_header_data_start += l_header_length; + /* << INDEX */ + // End of packet header position. Currently only represents the distance to start of packet + // Will be updated later by incrementing with packet start value + if + (p_pack_info) + { + p_pack_info->end_ph_pos = (OPJ_INT32)(l_current_data - p_src_data); + } + /* INDEX >> */ + * p_is_data_present = OPJ_TRUE; + *p_data_read = l_current_data - p_src_data; + return OPJ_TRUE; +} + +static opj_bool t2_read_packet_data( + opj_t2_v2_t* p_t2, + opj_tcd_tile_t *p_tile, + opj_pi_iterator_t *p_pi, + OPJ_BYTE *p_src_data, + OPJ_UINT32 * p_data_read, + OPJ_UINT32 p_max_length, + opj_packet_info_t *pack_info) +{ + OPJ_UINT32 bandno, cblkno; + OPJ_UINT32 l_nb_code_blocks; + OPJ_BYTE *l_current_data = p_src_data; + opj_tcd_band_t *l_band = 00; + opj_tcd_cblk_dec_t* l_cblk = 00; + opj_tcd_resolution_t* l_res = &p_tile->comps[p_pi->compno].resolutions[p_pi->resno]; + + l_band = l_res->bands; + for + (bandno = 0; bandno < l_res->numbands; ++bandno) + { + opj_tcd_precinct_t *l_prc = &l_band->precincts[p_pi->precno]; + + if + ((l_band->x1-l_band->x0 == 0)||(l_band->y1-l_band->y0 == 0)) + { + ++l_band; + continue; + } + l_nb_code_blocks = l_prc->cw * l_prc->ch; + l_cblk = l_prc->cblks.dec; + for + (cblkno = 0; cblkno < l_nb_code_blocks; ++cblkno) + { + opj_tcd_seg_t *l_seg = 00; + if + (!l_cblk->numnewpasses) + { + /* nothing to do */ + ++l_cblk; + continue; + } + if + (!l_cblk->numsegs) + { + l_seg = l_cblk->segs; + ++l_cblk->numsegs; + l_cblk->len = 0; + } + else + { + l_seg = &l_cblk->segs[l_cblk->numsegs - 1]; + if + (l_seg->numpasses == l_seg->maxpasses) + { + ++l_seg; + ++l_cblk->numsegs; + } + } + + do + { + if + (l_current_data + l_seg->newlen > p_src_data + p_max_length) + { + return OPJ_FALSE; + } + +#ifdef USE_JPWL + /* we need here a j2k handle to verify if making a check to + the validity of cblocks parameters is selected from user (-W) */ + + /* let's check that we are not exceeding */ + if ((cblk->len + seg->newlen) > 8192) { + opj_event_msg(t2->cinfo, EVT_WARNING, + "JPWL: segment too long (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", + seg->newlen, cblkno, precno, bandno, resno, compno); + if (!JPWL_ASSUME) { + opj_event_msg(t2->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return -999; + } + seg->newlen = 8192 - cblk->len; + opj_event_msg(t2->cinfo, EVT_WARNING, " - truncating segment to %d\n", seg->newlen); + break; + }; + +#endif /* USE_JPWL */ + + memcpy(l_cblk->data + l_cblk->len, l_current_data, l_seg->newlen); + if + (l_seg->numpasses == 0) + { + l_seg->data = &l_cblk->data; + l_seg->dataindex = l_cblk->len; + } + l_current_data += l_seg->newlen; + l_seg->numpasses += l_seg->numnewpasses; + l_cblk->numnewpasses -= l_seg->numnewpasses; + + l_seg->real_num_passes = l_seg->numpasses; + l_cblk->len += l_seg->newlen; + l_seg->len += l_seg->newlen; + if + (l_cblk->numnewpasses > 0) + { + ++l_seg; + ++l_cblk->numsegs; + } + } + while (l_cblk->numnewpasses > 0); + l_cblk->real_num_segs = l_cblk->numsegs; + ++l_cblk; + } + ++l_band; + } + *(p_data_read) = l_current_data - p_src_data; + return OPJ_TRUE; +} + +static opj_bool t2_skip_packet_data( + opj_t2_v2_t* p_t2, + opj_tcd_tile_t *p_tile, + opj_pi_iterator_t *p_pi, + OPJ_UINT32 * p_data_read, + OPJ_UINT32 p_max_length, + opj_packet_info_t *pack_info) +{ + OPJ_UINT32 bandno, cblkno; + OPJ_UINT32 l_nb_code_blocks; + opj_tcd_band_t *l_band = 00; + opj_tcd_cblk_dec_t* l_cblk = 00; + + opj_tcd_resolution_t* l_res = &p_tile->comps[p_pi->compno].resolutions[p_pi->resno]; + + *p_data_read = 0; + l_band = l_res->bands; + for + (bandno = 0; bandno < l_res->numbands; ++bandno) + { + opj_tcd_precinct_t *l_prc = &l_band->precincts[p_pi->precno]; + + if + ((l_band->x1-l_band->x0 == 0)||(l_band->y1-l_band->y0 == 0)) + { + ++l_band; + continue; + } + l_nb_code_blocks = l_prc->cw * l_prc->ch; + l_cblk = l_prc->cblks.dec; + for + (cblkno = 0; cblkno < l_nb_code_blocks; ++cblkno) + { + opj_tcd_seg_t *l_seg = 00; + if + (!l_cblk->numnewpasses) + { + /* nothing to do */ + ++l_cblk; + continue; + } + if + (!l_cblk->numsegs) + { + l_seg = l_cblk->segs; + ++l_cblk->numsegs; + l_cblk->len = 0; + } + else + { + l_seg = &l_cblk->segs[l_cblk->numsegs - 1]; + if + (l_seg->numpasses == l_seg->maxpasses) + { + ++l_seg; + ++l_cblk->numsegs; + } + } + + do + { + if + (* p_data_read + l_seg->newlen > p_max_length) + { + return OPJ_FALSE; + } + +#ifdef USE_JPWL + /* we need here a j2k handle to verify if making a check to + the validity of cblocks parameters is selected from user (-W) */ + + /* let's check that we are not exceeding */ + if ((cblk->len + seg->newlen) > 8192) { + opj_event_msg(t2->cinfo, EVT_WARNING, + "JPWL: segment too long (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", + seg->newlen, cblkno, precno, bandno, resno, compno); + if (!JPWL_ASSUME) { + opj_event_msg(t2->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return -999; + } + seg->newlen = 8192 - cblk->len; + opj_event_msg(t2->cinfo, EVT_WARNING, " - truncating segment to %d\n", seg->newlen); + break; + }; + +#endif /* USE_JPWL */ + *(p_data_read) += l_seg->newlen; + l_seg->numpasses += l_seg->numnewpasses; + l_cblk->numnewpasses -= l_seg->numnewpasses; + if + (l_cblk->numnewpasses > 0) + { + ++l_seg; + ++l_cblk->numsegs; + } + } + while (l_cblk->numnewpasses > 0); + ++l_cblk; + } + ++l_band; + } + return OPJ_TRUE; +} + + +static opj_bool t2_init_seg_v2(opj_tcd_cblk_dec_t* cblk, OPJ_UINT32 index, OPJ_UINT32 cblksty, OPJ_UINT32 first) +{ + opj_tcd_seg_t* seg = 00; + OPJ_UINT32 l_nb_segs = index + 1; + + if + (l_nb_segs > cblk->m_current_max_segs) + { + cblk->m_current_max_segs += J2K_DEFAULT_NB_SEGS; + cblk->segs = (opj_tcd_seg_t*) opj_realloc(cblk->segs, cblk->m_current_max_segs * sizeof(opj_tcd_seg_t)); + if + (! cblk->segs) + { + return OPJ_FALSE; + } + } + seg = &cblk->segs[index]; + memset(seg,0,sizeof(opj_tcd_seg_t)); + + if (cblksty & J2K_CCP_CBLKSTY_TERMALL) { + seg->maxpasses = 1; + } + else if (cblksty & J2K_CCP_CBLKSTY_LAZY) { + if (first) { + seg->maxpasses = 10; + } else { + seg->maxpasses = (((seg - 1)->maxpasses == 1) || ((seg - 1)->maxpasses == 10)) ? 2 : 1; + } + } else { + seg->maxpasses = 109; + } + return OPJ_TRUE; +} diff --git a/libopenjpeg/t2.h b/libopenjpeg/t2.h index 2151ba67..fd68331e 100644 --- a/libopenjpeg/t2.h +++ b/libopenjpeg/t2.h @@ -52,6 +52,19 @@ typedef struct opj_t2 { opj_cp_t *cp; } opj_t2_t; +/** +Tier-2 coding +*/ +typedef struct opj_t2_v2 { + /** codec context */ + opj_common_ptr cinfo; + + /** Encoding: pointer to the src image. Decoding: pointer to the dst image. */ + opj_image_t *image; + /** pointer to the image coding parameters */ + opj_cp_v2_t *cp; +} opj_t2_v2_t; + /** @name Exported functions */ /*@{*/ /* ----------------------------------------------------------------------- */ @@ -83,6 +96,25 @@ Decode the packets of a tile from a source buffer */ int t2_decode_packets(opj_t2_t *t2, unsigned char *src, int len, int tileno, opj_tcd_tile_t *tile, opj_codestream_info_t *cstr_info); +/** +Decode the packets of a tile from a source buffer +@param t2 T2 handle +@param src the source buffer +@param len length of the source buffer +@param tileno number that identifies the tile for which to decode the packets +@param tile tile for which to decode the packets + */ +opj_bool t2_decode_packets_v2(opj_t2_v2_t *t2, OPJ_UINT32 tileno,struct opj_tcd_tile *tile, OPJ_BYTE *src, OPJ_UINT32 * p_data_read, OPJ_UINT32 len, struct opj_codestream_info *cstr_info); + +/** + * Creates a Tier 2 handle + * + * @param p_image Source or destination image + * @param p_cp Image coding parameters. + * @return a new T2 handle if successful, NULL otherwise. +*/ +opj_t2_v2_t* t2_create_v2(struct opj_image *p_image, opj_cp_v2_t *p_cp); + /** Create a T2 handle @param cinfo Codec context info @@ -97,6 +129,12 @@ Destroy a T2 handle */ void t2_destroy(opj_t2_t *t2); +/** +Destroy a T2 handle +@param t2 T2 handle to destroy +*/ +void t2_destroy_v2(opj_t2_v2_t *t2); + /* ----------------------------------------------------------------------- */ /*@}*/ diff --git a/libopenjpeg/tcd.c b/libopenjpeg/tcd.c index 9c7bcc0d..5a0f0f4d 100644 --- a/libopenjpeg/tcd.c +++ b/libopenjpeg/tcd.c @@ -90,7 +90,43 @@ void tcd_dump(FILE *fd, opj_tcd_t *tcd, opj_tcd_image_t * img) { } fprintf(fd, "}\n"); } +/** +* Allocates memory for a decoding code block. +*/ +static opj_bool tcd_code_block_dec_allocate (opj_tcd_cblk_dec_t * p_code_block); +/** +Free the memory allocated for encoding +@param tcd TCD handle +*/ +static void tcd_free_tile(opj_tcd_v2_t *tcd); + + +opj_bool tcd_t2_decode ( + opj_tcd_v2_t *p_tcd, + OPJ_BYTE * p_src_data, + OPJ_UINT32 * p_data_read, + OPJ_UINT32 p_max_src_size, + opj_codestream_info_t *p_cstr_info + ); + +opj_bool tcd_t1_decode ( + opj_tcd_v2_t *p_tcd + ); + +opj_bool tcd_dwt_decode ( + opj_tcd_v2_t *p_tcd + ); + +opj_bool tcd_mct_decode ( + opj_tcd_v2_t *p_tcd + ); + +opj_bool tcd_dc_level_shift_decode ( + opj_tcd_v2_t *p_tcd + ); + +void tcd_code_block_dec_deallocate (opj_tcd_precinct_t * p_precinct); /* ----------------------------------------------------------------------- */ /** @@ -110,6 +146,33 @@ opj_tcd_t* tcd_create(opj_common_ptr cinfo) { return tcd; } +/** +Create a new TCD handle +*/ +opj_tcd_v2_t* tcd_create_v2(opj_bool p_is_decoder) +{ + opj_tcd_v2_t *l_tcd = 00; + + /* create the tcd structure */ + l_tcd = (opj_tcd_v2_t*) opj_malloc(sizeof(opj_tcd_v2_t)); + if + (!l_tcd) + { + return 00; + } + memset(l_tcd,0,sizeof(opj_tcd_v2_t)); + l_tcd->m_is_decoder = p_is_decoder ? 1 : 0; + l_tcd->tcd_image = (opj_tcd_image_t*)opj_malloc(sizeof(opj_tcd_image_t)); + if + (!l_tcd->tcd_image) + { + opj_free(l_tcd); + return 00; + } + memset(l_tcd->tcd_image,0,sizeof(opj_tcd_image_t)); + return l_tcd; +} + /** Destroy a previously created TCD handle */ @@ -1520,4 +1583,1119 @@ void tcd_free_decode_tile(opj_tcd_t *tcd, int tileno) { } +opj_bool tcd_init_v2( + opj_tcd_v2_t *p_tcd, + opj_image_t * p_image, + opj_cp_v2_t * p_cp + ) +{ + OPJ_UINT32 l_tile_comp_size; + p_tcd->image = p_image; + p_tcd->cp = p_cp; + p_tcd->tcd_image->tiles = (opj_tcd_tile_t *) opj_malloc(sizeof(opj_tcd_tile_t)); + + if + (! p_tcd->tcd_image->tiles) + { + return OPJ_FALSE; + } + memset(p_tcd->tcd_image->tiles,0, sizeof(opj_tcd_tile_t)); + + l_tile_comp_size = p_image->numcomps * sizeof(opj_tcd_tilecomp_t); + p_tcd->tcd_image->tiles->comps = (opj_tcd_tilecomp_t *) opj_malloc(l_tile_comp_size); + if + (! p_tcd->tcd_image->tiles->comps ) + { + return OPJ_FALSE; + } + memset( p_tcd->tcd_image->tiles->comps , 0 , l_tile_comp_size); + p_tcd->tcd_image->tiles->numcomps = p_image->numcomps; + p_tcd->tp_pos = p_cp->m_specific_param.m_enc.m_tp_pos; + return OPJ_TRUE; +} + +/** +Destroy a previously created TCD handle +*/ +void tcd_destroy_v2(opj_tcd_v2_t *tcd) { + if + (tcd) + { + tcd_free_tile(tcd); + if + (tcd->tcd_image) + { + opj_free(tcd->tcd_image); + tcd->tcd_image = 00; + } + opj_free(tcd); + } +} + +/* ----------------------------------------------------------------------- */ +/** + * Initialize the tile coder and may reuse some meory. + * @param p_tcd TCD handle. + * @param p_image raw image. + * @param p_cp coding parameters. + * @param p_tile_no current tile index to encode. + * + * @return true if the encoding values could be set (false otherwise). +*/ +#define MACRO_TCD_ALLOCATE(FUNCTION,TYPE,FRACTION,ELEMENT,FUNCTION_ELEMENT) \ +opj_bool FUNCTION \ + ( \ + opj_tcd_v2_t *p_tcd, \ + OPJ_UINT32 p_tile_no \ + ) \ +{ \ + OPJ_UINT32 (*l_gain_ptr)(OPJ_UINT32) = 00; \ + OPJ_UINT32 compno, resno, bandno, precno, cblkno; \ + opj_tcp_v2_t * l_tcp = 00; \ + opj_cp_v2_t * l_cp = 00; \ + opj_tcd_tile_t * l_tile = 00; \ + opj_tccp_t *l_tccp = 00; \ + opj_tcd_tilecomp_t *l_tilec = 00; \ + opj_image_comp_t * l_image_comp = 00; \ + opj_tcd_resolution_t *l_res = 00; \ + opj_tcd_band_t *l_band = 00; \ + opj_stepsize_t * l_step_size = 00; \ + opj_tcd_precinct_t *l_current_precinct = 00; \ + TYPE* l_code_block = 00; \ + opj_image_t * l_image = 00; \ + OPJ_UINT32 p,q; \ + OPJ_UINT32 l_level_no; \ + OPJ_UINT32 l_pdx, l_pdy; \ + OPJ_UINT32 l_gain; \ + OPJ_INT32 l_x0b, l_y0b; \ + /* extent of precincts , top left, bottom right**/ \ + OPJ_INT32 l_tl_prc_x_start, l_tl_prc_y_start, l_br_prc_x_end, l_br_prc_y_end; \ + /* number of precinct for a resolution */ \ + OPJ_UINT32 l_nb_precincts; \ + /* room needed to store l_nb_precinct precinct for a resolution */ \ + OPJ_UINT32 l_nb_precinct_size; \ + /* number of code blocks for a precinct*/ \ + OPJ_UINT32 l_nb_code_blocks; \ + /* room needed to store l_nb_code_blocks code blocks for a precinct*/ \ + OPJ_UINT32 l_nb_code_blocks_size; \ + /* size of data for a tile */ \ + OPJ_UINT32 l_data_size; \ + l_cp = p_tcd->cp; \ + l_tcp = &(l_cp->tcps[p_tile_no]); \ + l_tile = p_tcd->tcd_image->tiles; \ + l_tccp = l_tcp->tccps; \ + l_tilec = l_tile->comps; \ + l_image = p_tcd->image; \ + l_image_comp = p_tcd->image->comps; \ + \ + p = p_tile_no % l_cp->tw; /* tile coordinates */ \ + q = p_tile_no / l_cp->tw; \ + \ + /* 4 borders of the tile rescale on the image if necessary */ \ + l_tile->x0 = int_max(l_cp->tx0 + p * l_cp->tdx, l_image->x0); \ + l_tile->y0 = int_max(l_cp->ty0 + q * l_cp->tdy, l_image->y0); \ + l_tile->x1 = int_min(l_cp->tx0 + (p + 1) * l_cp->tdx, l_image->x1); \ + l_tile->y1 = int_min(l_cp->ty0 + (q + 1) * l_cp->tdy, l_image->y1); \ + /*tile->numcomps = image->numcomps; */ \ + for \ + (compno = 0; compno < l_tile->numcomps; ++compno) \ + { \ + /* border of each l_tile component (global) */ \ + l_tilec->x0 = int_ceildiv(l_tile->x0, l_image_comp->dx); \ + l_tilec->y0 = int_ceildiv(l_tile->y0, l_image_comp->dy); \ + l_tilec->x1 = int_ceildiv(l_tile->x1, l_image_comp->dx); \ + l_tilec->y1 = int_ceildiv(l_tile->y1, l_image_comp->dy); \ + \ + l_data_size = (l_tilec->x1 - l_tilec->x0) \ + * (l_tilec->y1 - l_tilec->y0) * sizeof(OPJ_UINT32 ); \ + l_tilec->numresolutions = l_tccp->numresolutions; \ + if \ + (l_tccp->numresolutions < l_cp->m_specific_param.m_dec.m_reduce)\ + { \ + l_tilec->minimum_num_resolutions = 1; \ + } \ + else \ + { \ + l_tilec->minimum_num_resolutions = l_tccp->numresolutions - l_cp->m_specific_param.m_dec.m_reduce;\ + } \ + if \ + (l_tilec->data == 00) \ + { \ + l_tilec->data = (OPJ_INT32 *) opj_aligned_malloc(l_data_size); \ + if \ + (! l_tilec->data ) \ + { \ + return OPJ_FALSE; \ + } \ + l_tilec->data_size = l_data_size; \ + } \ + else if \ + (l_data_size > l_tilec->data_size) \ + { \ + l_tilec->data = (OPJ_INT32 *) opj_realloc(l_tilec->data, l_data_size);\ + if \ + (! l_tilec->data) \ + { \ + return OPJ_FALSE; \ + } \ + l_tilec->data_size = l_data_size; \ + } \ + l_data_size = l_tilec->numresolutions * sizeof(opj_tcd_resolution_t);\ + if \ + (l_tilec->resolutions == 00) \ + { \ + l_tilec->resolutions = (opj_tcd_resolution_t *) opj_malloc(l_data_size);\ + if \ + (! l_tilec->resolutions ) \ + { \ + return OPJ_FALSE; \ + } \ + l_tilec->resolutions_size = l_data_size; \ + memset(l_tilec->resolutions,0,l_data_size); \ + } \ + else if \ + (l_data_size > l_tilec->resolutions_size) \ + { \ + l_tilec->resolutions = (opj_tcd_resolution_t *) opj_realloc(l_tilec->resolutions, l_data_size);\ + if \ + (! l_tilec->resolutions) \ + { \ + return OPJ_FALSE; \ + } \ + memset(((OPJ_BYTE*) l_tilec->resolutions)+l_tilec->resolutions_size,0,l_data_size - l_tilec->resolutions_size);\ + l_tilec->resolutions_size = l_data_size; \ + } \ + l_level_no = l_tilec->numresolutions - 1; \ + l_res = l_tilec->resolutions; \ + l_step_size = l_tccp->stepsizes; \ + if \ + (l_tccp->qmfbid == 0) \ + { \ + l_gain_ptr = &dwt_getgain_real; \ + } \ + else \ + { \ + l_gain_ptr = &dwt_getgain; \ + } \ + for \ + (resno = 0; resno < l_tilec->numresolutions; ++resno) \ + { \ + OPJ_INT32 tlcbgxstart, tlcbgystart, brcbgxend, brcbgyend; \ + OPJ_UINT32 cbgwidthexpn, cbgheightexpn; \ + OPJ_UINT32 cblkwidthexpn, cblkheightexpn; \ + /* border for each resolution level (global) */ \ + l_res->x0 = int_ceildivpow2(l_tilec->x0, l_level_no); \ + l_res->y0 = int_ceildivpow2(l_tilec->y0, l_level_no); \ + l_res->x1 = int_ceildivpow2(l_tilec->x1, l_level_no); \ + l_res->y1 = int_ceildivpow2(l_tilec->y1, l_level_no); \ + /* p. 35, table A-23, ISO/IEC FDIS154444-1 : 2000 (18 august 2000) */\ + l_pdx = l_tccp->prcw[resno]; \ + l_pdy = l_tccp->prch[resno]; \ + /* p. 64, B.6, ISO/IEC FDIS15444-1 : 2000 (18 august 2000) */ \ + l_tl_prc_x_start = int_floordivpow2(l_res->x0, l_pdx) << l_pdx; \ + l_tl_prc_y_start = int_floordivpow2(l_res->y0, l_pdy) << l_pdy; \ + l_br_prc_x_end = int_ceildivpow2(l_res->x1, l_pdx) << l_pdx; \ + l_br_prc_y_end = int_ceildivpow2(l_res->y1, l_pdy) << l_pdy; \ + \ + l_res->pw = (l_res->x0 == l_res->x1) ? 0 : ((l_br_prc_x_end - l_tl_prc_x_start) >> l_pdx);\ + l_res->ph = (l_res->y0 == l_res->y1) ? 0 : ((l_br_prc_y_end - l_tl_prc_y_start) >> l_pdy);\ + l_nb_precincts = l_res->pw * l_res->ph; \ + l_nb_precinct_size = l_nb_precincts * sizeof(opj_tcd_precinct_t);\ + if \ + (resno == 0) \ + { \ + tlcbgxstart = l_tl_prc_x_start; \ + tlcbgystart = l_tl_prc_y_start; \ + brcbgxend = l_br_prc_x_end; \ + brcbgyend = l_br_prc_y_end; \ + cbgwidthexpn = l_pdx; \ + cbgheightexpn = l_pdy; \ + l_res->numbands = 1; \ + } \ + else \ + { \ + tlcbgxstart = int_ceildivpow2(l_tl_prc_x_start, 1); \ + tlcbgystart = int_ceildivpow2(l_tl_prc_y_start, 1); \ + brcbgxend = int_ceildivpow2(l_br_prc_x_end, 1); \ + brcbgyend = int_ceildivpow2(l_br_prc_y_end, 1); \ + cbgwidthexpn = l_pdx - 1; \ + cbgheightexpn = l_pdy - 1; \ + l_res->numbands = 3; \ + } \ + \ + cblkwidthexpn = uint_min(l_tccp->cblkw, cbgwidthexpn); \ + cblkheightexpn = uint_min(l_tccp->cblkh, cbgheightexpn); \ + l_band = l_res->bands; \ + for \ + (bandno = 0; bandno < l_res->numbands; ++bandno) \ + { \ + OPJ_INT32 numbps; \ + if \ + (resno == 0) \ + { \ + l_band->bandno = 0 ; \ + l_band->x0 = int_ceildivpow2(l_tilec->x0, l_level_no); \ + l_band->y0 = int_ceildivpow2(l_tilec->y0, l_level_no); \ + l_band->x1 = int_ceildivpow2(l_tilec->x1, l_level_no); \ + l_band->y1 = int_ceildivpow2(l_tilec->y1, l_level_no); \ + } \ + else \ + { \ + l_band->bandno = bandno + 1; \ + /* x0b = 1 if bandno = 1 or 3 */ \ + l_x0b = l_band->bandno&1; \ + /* y0b = 1 if bandno = 2 or 3 */ \ + l_y0b = (l_band->bandno)>>1; \ + /* l_band border (global) */ \ + l_band->x0 = int_ceildivpow2(l_tilec->x0 - (1 << l_level_no) * l_x0b, l_level_no + 1);\ + l_band->y0 = int_ceildivpow2(l_tilec->y0 - (1 << l_level_no) * l_y0b, l_level_no + 1);\ + l_band->x1 = int_ceildivpow2(l_tilec->x1 - (1 << l_level_no) * l_x0b, l_level_no + 1);\ + l_band->y1 = int_ceildivpow2(l_tilec->y1 - (1 << l_level_no) * l_y0b, l_level_no + 1);\ + } \ + /** avoid an if with storing function pointer */ \ + l_gain = (*l_gain_ptr) (l_band->bandno); \ + numbps = l_image_comp->prec + l_gain; \ + l_band->stepsize = (OPJ_FLOAT32)(((1.0 + l_step_size->mant / 2048.0) * pow(2.0, (OPJ_INT32) (numbps - l_step_size->expn)))) * FRACTION;\ + l_band->numbps = l_step_size->expn + l_tccp->numgbits - 1; /* WHY -1 ? */\ + if \ + (! l_band->precincts) \ + { \ + l_band->precincts = (opj_tcd_precinct_t *) opj_malloc(/*3 * */ l_nb_precinct_size);\ + if \ + (! l_band->precincts) \ + { \ + return OPJ_FALSE; \ + } \ + memset(l_band->precincts,0,l_nb_precinct_size); \ + l_band->precincts_data_size = l_nb_precinct_size; \ + } \ + else if \ + (l_band->precincts_data_size < l_nb_precinct_size) \ + { \ + l_band->precincts = (opj_tcd_precinct_t *) opj_realloc(l_band->precincts,/*3 * */ l_nb_precinct_size);\ + if \ + (! l_band->precincts) \ + { \ + return OPJ_FALSE; \ + } \ + memset(((OPJ_BYTE *) l_band->precincts) + l_band->precincts_data_size,0,l_nb_precinct_size - l_band->precincts_data_size);\ + l_band->precincts_data_size = l_nb_precinct_size; \ + } \ + l_current_precinct = l_band->precincts; \ + for \ + (precno = 0; precno < l_nb_precincts; ++precno) \ + { \ + OPJ_INT32 tlcblkxstart, tlcblkystart, brcblkxend, brcblkyend; \ + OPJ_INT32 cbgxstart = tlcbgxstart + (precno % l_res->pw) * (1 << cbgwidthexpn);\ + OPJ_INT32 cbgystart = tlcbgystart + (precno / l_res->pw) * (1 << cbgheightexpn);\ + OPJ_INT32 cbgxend = cbgxstart + (1 << cbgwidthexpn); \ + OPJ_INT32 cbgyend = cbgystart + (1 << cbgheightexpn); \ + /* precinct size (global) */ \ + l_current_precinct->x0 = int_max(cbgxstart, l_band->x0);\ + l_current_precinct->y0 = int_max(cbgystart, l_band->y0);\ + l_current_precinct->x1 = int_min(cbgxend, l_band->x1); \ + l_current_precinct->y1 = int_min(cbgyend, l_band->y1); \ + tlcblkxstart = int_floordivpow2(l_current_precinct->x0, cblkwidthexpn) << cblkwidthexpn;\ + tlcblkystart = int_floordivpow2(l_current_precinct->y0, cblkheightexpn) << cblkheightexpn;\ + brcblkxend = int_ceildivpow2(l_current_precinct->x1, cblkwidthexpn) << cblkwidthexpn;\ + brcblkyend = int_ceildivpow2(l_current_precinct->y1, cblkheightexpn) << cblkheightexpn;\ + l_current_precinct->cw = (brcblkxend - tlcblkxstart) >> cblkwidthexpn;\ + l_current_precinct->ch = (brcblkyend - tlcblkystart) >> cblkheightexpn;\ + l_nb_code_blocks = l_current_precinct->cw * l_current_precinct->ch;\ + l_nb_code_blocks_size = l_nb_code_blocks * sizeof(TYPE);\ + if \ + (! l_current_precinct->cblks.ELEMENT) \ + { \ + l_current_precinct->cblks.ELEMENT = (TYPE*) opj_malloc(l_nb_code_blocks_size);\ + if \ + (! l_current_precinct->cblks.ELEMENT ) \ + { \ + return OPJ_FALSE; \ + } \ + memset(l_current_precinct->cblks.ELEMENT,0,l_nb_code_blocks_size);\ + l_current_precinct->block_size = l_nb_code_blocks_size;\ + } \ + else if \ + (l_nb_code_blocks_size > l_current_precinct->block_size)\ + { \ + l_current_precinct->cblks.ELEMENT = (TYPE*) \ + opj_realloc(l_current_precinct->cblks.ELEMENT, l_nb_code_blocks_size);\ + if \ + (! l_current_precinct->cblks.ELEMENT ) \ + { \ + return OPJ_FALSE; \ + } \ + memset(((OPJ_BYTE *) l_current_precinct->cblks.ELEMENT) + l_current_precinct->block_size\ + ,0 \ + ,l_nb_code_blocks_size - l_current_precinct->block_size);\ + l_current_precinct->block_size = l_nb_code_blocks_size;\ + } \ + if \ + (! l_current_precinct->incltree) \ + { \ + l_current_precinct->incltree = tgt_create(l_current_precinct->cw,\ + l_current_precinct->ch);\ + } \ + else \ + { \ + l_current_precinct->incltree = tgt_init(l_current_precinct->incltree,\ + l_current_precinct->cw, \ + l_current_precinct->ch);\ + } \ + if \ + (! l_current_precinct->incltree) \ + { \ + return OPJ_FALSE; \ + } \ + if \ + (! l_current_precinct->imsbtree) \ + { \ + l_current_precinct->imsbtree = tgt_create( \ + l_current_precinct->cw,\ + l_current_precinct->ch);\ + } \ + else \ + { \ + l_current_precinct->imsbtree = tgt_init( \ + l_current_precinct->imsbtree,\ + l_current_precinct->cw,\ + l_current_precinct->ch);\ + } \ + if \ + (! l_current_precinct->imsbtree) \ + { \ + return OPJ_FALSE; \ + } \ + l_code_block = l_current_precinct->cblks.ELEMENT; \ + for \ + (cblkno = 0; cblkno < l_nb_code_blocks; ++cblkno) \ + { \ + OPJ_INT32 cblkxstart = tlcblkxstart + (cblkno % l_current_precinct->cw) * (1 << cblkwidthexpn);\ + OPJ_INT32 cblkystart = tlcblkystart + (cblkno / l_current_precinct->cw) * (1 << cblkheightexpn);\ + OPJ_INT32 cblkxend = cblkxstart + (1 << cblkwidthexpn); \ + OPJ_INT32 cblkyend = cblkystart + (1 << cblkheightexpn); \ + /* code-block size (global) */ \ + l_code_block->x0 = int_max(cblkxstart, l_current_precinct->x0);\ + l_code_block->y0 = int_max(cblkystart, l_current_precinct->y0);\ + l_code_block->x1 = int_min(cblkxend, l_current_precinct->x1);\ + l_code_block->y1 = int_min(cblkyend, l_current_precinct->y1);\ + if \ + (! FUNCTION_ELEMENT(l_code_block)) \ + { \ + return OPJ_FALSE; \ + } \ + ++l_code_block; \ + } \ + ++l_current_precinct; \ + } /* precno */ \ + ++l_band; \ + ++l_step_size; \ + } /* bandno */ \ + ++l_res; \ + --l_level_no; \ + } /* resno */ \ + ++l_tccp; \ + ++l_tilec; \ + ++l_image_comp; \ + } /* compno */ \ + return OPJ_TRUE; \ +} \ + +// V2 ENCODE MACRO_TCD_ALLOCATE(tcd_init_encode_tile,opj_tcd_cblk_enc_t,1.f,enc,tcd_code_block_enc_allocate) +MACRO_TCD_ALLOCATE(tcd_init_decode_tile,opj_tcd_cblk_dec_t,0.5f,dec,tcd_code_block_dec_allocate) + +#undef MACRO_TCD_ALLOCATE + + +OPJ_UINT32 tcd_get_decoded_tile_size ( + opj_tcd_v2_t *p_tcd + ) +{ + OPJ_UINT32 i; + OPJ_UINT32 l_data_size = 0; + opj_image_comp_t * l_img_comp = 00; + opj_tcd_tilecomp_t * l_tile_comp = 00; + opj_tcd_resolution_t * l_res = 00; + OPJ_UINT32 l_size_comp, l_remaining; + + l_tile_comp = p_tcd->tcd_image->tiles->comps; + l_img_comp = p_tcd->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_res = l_tile_comp->resolutions + l_tile_comp->minimum_num_resolutions - 1; + l_data_size += l_size_comp * (l_res->x1 - l_res->x0) * (l_res->y1 - l_res->y0); + ++l_img_comp; + ++l_tile_comp; + } + return l_data_size; +} + + +opj_bool tcd_decode_tile_v2( + opj_tcd_v2_t *p_tcd, + OPJ_BYTE *p_src, + OPJ_UINT32 p_max_length, + OPJ_UINT32 p_tile_no, + opj_codestream_info_t *p_cstr_info) +{ + OPJ_UINT32 l_data_read; + p_tcd->tcd_tileno = p_tile_no; + p_tcd->tcp = &(p_tcd->cp->tcps[p_tile_no]); + + /* INDEX >> */ + if(p_cstr_info) { + OPJ_UINT32 resno, compno, numprec = 0; + for (compno = 0; compno < (OPJ_UINT32) p_cstr_info->numcomps; compno++) { + opj_tcp_v2_t *tcp = &p_tcd->cp->tcps[0]; + opj_tccp_t *tccp = &tcp->tccps[compno]; + opj_tcd_tilecomp_t *tilec_idx = &p_tcd->tcd_image->tiles->comps[compno]; + for (resno = 0; resno < tilec_idx->numresolutions; resno++) { + opj_tcd_resolution_t *res_idx = &tilec_idx->resolutions[resno]; + p_cstr_info->tile[p_tile_no].pw[resno] = res_idx->pw; + p_cstr_info->tile[p_tile_no].ph[resno] = res_idx->ph; + numprec += res_idx->pw * res_idx->ph; + p_cstr_info->tile[p_tile_no].pdx[resno] = tccp->prcw[resno]; + p_cstr_info->tile[p_tile_no].pdy[resno] = tccp->prch[resno]; + } + } + p_cstr_info->tile[p_tile_no].packet = (opj_packet_info_t *) opj_malloc(p_cstr_info->numlayers * numprec * sizeof(opj_packet_info_t)); + p_cstr_info->packno = 0; + } + /* << INDEX */ + + /*--------------TIER2------------------*/ + // FIXME _ProfStart(PGROUP_T2); + l_data_read = 0; + if + (! tcd_t2_decode(p_tcd,p_src,&l_data_read,p_max_length,p_cstr_info)) + { + return OPJ_FALSE; + } + // FIXME _ProfStop(PGROUP_T2); + + /*------------------TIER1-----------------*/ + + // FIXME _ProfStart(PGROUP_T1); + if + (! tcd_t1_decode(p_tcd)) + { + return OPJ_FALSE; + } + // FIXME _ProfStop(PGROUP_T1); + + /*----------------DWT---------------------*/ + + // FIXME _ProfStart(PGROUP_DWT); + if + (! tcd_dwt_decode(p_tcd)) + { + return OPJ_FALSE; + } + // FIXME _ProfStop(PGROUP_DWT); + + /*----------------MCT-------------------*/ + // FIXME _ProfStart(PGROUP_MCT); + if + (! tcd_mct_decode(p_tcd)) + { + return OPJ_FALSE; + } + // FIXME _ProfStop(PGROUP_MCT); + + // FIXME _ProfStart(PGROUP_DC_SHIFT); + if + (! tcd_dc_level_shift_decode(p_tcd)) + { + return OPJ_FALSE; + } + // FIXME _ProfStop(PGROUP_DC_SHIFT); + + + /*---------------TILE-------------------*/ + return OPJ_TRUE; +} + +opj_bool tcd_update_tile_data ( + opj_tcd_v2_t *p_tcd, + OPJ_BYTE * p_dest, + OPJ_UINT32 p_dest_length + ) +{ + OPJ_UINT32 i,j,k,l_data_size = 0; + opj_image_comp_t * l_img_comp = 00; + opj_tcd_tilecomp_t * l_tilec = 00; + opj_tcd_resolution_t * l_res; + OPJ_UINT32 l_size_comp, l_remaining; + OPJ_UINT32 l_stride, l_width,l_height; + + l_data_size = tcd_get_decoded_tile_size(p_tcd); + if + (l_data_size > p_dest_length) + { + return OPJ_FALSE; + } + + l_tilec = p_tcd->tcd_image->tiles->comps; + l_img_comp = p_tcd->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) */ + l_res = l_tilec->resolutions + l_img_comp->resno_decoded; + l_width = (l_res->x1 - l_res->x0); + l_height = (l_res->y1 - l_res->y0); + l_stride = (l_tilec->x1 - l_tilec->x0) - l_width; + if + (l_remaining) + { + ++l_size_comp; + } + if + (l_size_comp == 3) + { + l_size_comp = 4; + } + switch + (l_size_comp) + { + case 1: + { + OPJ_CHAR * l_dest_ptr = (OPJ_CHAR *) p_dest; + const OPJ_INT32 * l_src_ptr = l_tilec->data; + if + (l_img_comp->sgnd) + { + for + (j=0;jdata; + OPJ_INT16 * l_dest_ptr = (OPJ_INT16 *) p_dest; + if + (l_img_comp->sgnd) + { + for + (j=0;jdata; + for + (j=0;jtcd_image) + { + return; + } + if + (p_tcd->m_is_decoder) + { + l_tcd_code_block_deallocate = tcd_code_block_dec_deallocate; + } + else + { + // FIXME l_tcd_code_block_deallocate = tcd_code_block_enc_deallocate; + } + + + l_tile = p_tcd->tcd_image->tiles; + if + (! l_tile) + { + return; + } + l_tile_comp = l_tile->comps; + + for + (compno = 0; compno < l_tile->numcomps; ++compno) + { + l_res = l_tile_comp->resolutions; + if + (l_res) + { + l_nb_resolutions = l_tile_comp->resolutions_size / sizeof(opj_tcd_resolution_t); + for + (resno = 0; resno < l_nb_resolutions; ++resno) + { + l_band = l_res->bands; + for + (bandno = 0; bandno < 3; ++bandno) + { + l_precinct = l_band->precincts; + if + (l_precinct) + { + l_nb_precincts = l_band->precincts_data_size / sizeof(opj_tcd_precinct_t); + for + (precno = 0; precno < l_nb_precincts; ++precno) + { + tgt_destroy(l_precinct->incltree); + l_precinct->incltree = 00; + tgt_destroy(l_precinct->imsbtree); + l_precinct->imsbtree = 00; + (*l_tcd_code_block_deallocate) (l_precinct); + ++l_precinct; + } + opj_free(l_band->precincts); + l_band->precincts = 00; + } + ++l_band; + } /* for (resno */ + ++l_res; + } + opj_free(l_tile_comp->resolutions); + l_tile_comp->resolutions = 00; + } + if + (l_tile_comp->data) + { + opj_aligned_free(l_tile_comp->data); + l_tile_comp->data = 00; + } + ++l_tile_comp; + } + opj_free(l_tile->comps); + l_tile->comps = 00; + opj_free(p_tcd->tcd_image->tiles); + p_tcd->tcd_image->tiles = 00; +} + + +/** + * Allocates memory for a decoding code block. + */ +opj_bool tcd_code_block_dec_allocate (opj_tcd_cblk_dec_t * p_code_block) +{ + OPJ_UINT32 l_seg_size; + + if + (! p_code_block->data) + { + p_code_block->data = (OPJ_BYTE*) opj_malloc(8192); + if + (! p_code_block->data) + { + return OPJ_FALSE; + } + l_seg_size = J2K_DEFAULT_NB_SEGS * sizeof(opj_tcd_seg_t); + p_code_block->segs = (opj_tcd_seg_t *) opj_malloc(l_seg_size); + if + (! p_code_block->segs) + { + return OPJ_FALSE; + } + memset(p_code_block->segs,0,l_seg_size); + p_code_block->m_current_max_segs = J2K_DEFAULT_NB_SEGS; + } + // TODO + //p_code_block->numsegs = 0; + return OPJ_TRUE; +} + +opj_bool tcd_t2_decode ( + opj_tcd_v2_t *p_tcd, + OPJ_BYTE * p_src_data, + OPJ_UINT32 * p_data_read, + OPJ_UINT32 p_max_src_size, + opj_codestream_info_t *p_cstr_info + ) +{ + opj_t2_v2_t * l_t2; + + l_t2 = t2_create_v2(p_tcd->image, p_tcd->cp); + if + (l_t2 == 00) + { + return OPJ_FALSE; + } + + if + (! t2_decode_packets_v2( + l_t2, + p_tcd->tcd_tileno, + p_tcd->tcd_image->tiles, + p_src_data, + p_data_read, + p_max_src_size, + p_cstr_info)) + { + t2_destroy_v2(l_t2); + return OPJ_FALSE; + } + t2_destroy_v2(l_t2); + + /*---------------CLEAN-------------------*/ + return OPJ_TRUE; +} + +opj_bool tcd_t1_decode ( + opj_tcd_v2_t *p_tcd + ) +{ + OPJ_UINT32 compno; + opj_t1_t * l_t1; + opj_tcd_tile_t * l_tile = p_tcd->tcd_image->tiles; + opj_tcd_tilecomp_t* l_tile_comp = l_tile->comps; + opj_tccp_t * l_tccp = p_tcd->tcp->tccps; + + + l_t1 = t1_create_v2(); + if + (l_t1 == 00) + { + return OPJ_FALSE; + } + for + (compno = 0; compno < l_tile->numcomps; ++compno) + { + /* The +3 is headroom required by the vectorized DWT */ + t1_decode_cblks(l_t1, l_tile_comp, l_tccp); + ++l_tile_comp; + ++l_tccp; + } + t1_destroy_v2(l_t1); + return OPJ_TRUE; +} + + +opj_bool tcd_dwt_decode ( + opj_tcd_v2_t *p_tcd + ) +{ + OPJ_UINT32 compno; + opj_tcd_tile_t * l_tile = p_tcd->tcd_image->tiles; + opj_tcd_tilecomp_t * l_tile_comp = l_tile->comps; + opj_tccp_t * l_tccp = p_tcd->tcp->tccps; + opj_image_comp_t * l_img_comp = p_tcd->image->comps; + + for + (compno = 0; compno < l_tile->numcomps; compno++) + { + /* + if (tcd->cp->reduce != 0) { + tcd->image->comps[compno].resno_decoded = + tile->comps[compno].numresolutions - tcd->cp->reduce - 1; + if (tcd->image->comps[compno].resno_decoded < 0) + { + return false; + } + } + numres2decode = tcd->image->comps[compno].resno_decoded + 1; + if(numres2decode > 0){ + */ + if + (l_tccp->qmfbid == 1) + { + if + (! dwt_decode(l_tile_comp, l_img_comp->resno_decoded+1)) + { + return OPJ_FALSE; + } + } + else + { + if + (! dwt_decode_real(l_tile_comp, l_img_comp->resno_decoded+1)) + { + return OPJ_FALSE; + } + } + ++l_tile_comp; + ++l_img_comp; + ++l_tccp; + } + return OPJ_TRUE; +} +opj_bool tcd_mct_decode ( + opj_tcd_v2_t *p_tcd + ) +{ + opj_tcd_tile_t * l_tile = p_tcd->tcd_image->tiles; + opj_tcp_v2_t * l_tcp = p_tcd->tcp; + opj_tcd_tilecomp_t * l_tile_comp = l_tile->comps; + OPJ_UINT32 l_samples,i; + + if + (! l_tcp->mct) + { + return OPJ_TRUE; + } + l_samples = (l_tile_comp->x1 - l_tile_comp->x0) * (l_tile_comp->y1 - l_tile_comp->y0); + if + (l_tcp->mct == 2) + { + OPJ_BYTE ** l_data; + if + (! l_tcp->m_mct_decoding_matrix) + { + return OPJ_TRUE; + } + l_data = (OPJ_BYTE **) opj_malloc(l_tile->numcomps*sizeof(OPJ_BYTE*)); + if + (! l_data) + { + return OPJ_FALSE; + } + for + (i=0;inumcomps;++i) + { + l_data[i] = (OPJ_BYTE*) l_tile_comp->data; + ++l_tile_comp; + } + if + (! mct_decode_custom( // MCT data + (OPJ_BYTE*) l_tcp->m_mct_decoding_matrix, + // size of components + l_samples, + // components + l_data, + // nb of components (i.e. size of pData) + l_tile->numcomps, + // tells if the data is signed + p_tcd->image->comps->sgnd)) + { + opj_free(l_data); + return OPJ_FALSE; + } + opj_free(l_data); + } + else + { + if + (l_tcp->tccps->qmfbid == 1) + { + mct_decode( + l_tile->comps[0].data, + l_tile->comps[1].data, + l_tile->comps[2].data, + l_samples); + } + else + { + mct_decode_real( + (float*)l_tile->comps[0].data, + (float*)l_tile->comps[1].data, + (float*)l_tile->comps[2].data, + l_samples); + } + } + return OPJ_TRUE; +} + + +opj_bool tcd_dc_level_shift_decode ( + opj_tcd_v2_t *p_tcd + ) +{ + OPJ_UINT32 compno; + opj_tcd_tilecomp_t * l_tile_comp = 00; + opj_tccp_t * l_tccp = 00; + opj_image_comp_t * l_img_comp = 00; + opj_tcd_resolution_t* l_res = 00; + opj_tcp_v2_t * l_tcp = 00; + opj_tcd_tile_t * l_tile; + OPJ_UINT32 l_width,l_height,i,j; + OPJ_INT32 * l_current_ptr; + OPJ_INT32 l_min, l_max; + OPJ_UINT32 l_stride; + + l_tile = p_tcd->tcd_image->tiles; + l_tile_comp = l_tile->comps; + l_tcp = p_tcd->tcp; + l_tccp = p_tcd->tcp->tccps; + l_img_comp = p_tcd->image->comps; + + for + (compno = 0; compno < l_tile->numcomps; compno++) + { + l_res = l_tile_comp->resolutions + l_img_comp->resno_decoded; + l_width = (l_res->x1 - l_res->x0); + l_height = (l_res->y1 - l_res->y0); + l_stride = (l_tile_comp->x1 - l_tile_comp->x0) - l_width; + if + (l_img_comp->sgnd) + { + l_min = -(1 << (l_img_comp->prec - 1)); + l_max = (1 << (l_img_comp->prec - 1)) - 1; + } + else + { + l_min = 0; + l_max = (1 << l_img_comp->prec) - 1; + } + l_current_ptr = l_tile_comp->data; + if + (l_tccp->qmfbid == 1) + { + for + (j=0;jm_dc_level_shift, l_min, l_max); + ++l_current_ptr; + } + l_current_ptr += l_stride; + } + } + else + { + for + (j=0;jm_dc_level_shift, l_min, l_max); ; + ++l_current_ptr; + } + l_current_ptr += l_stride; + } + } + ++l_img_comp; + ++l_tccp; + ++l_tile_comp; + } + return OPJ_TRUE; +} + + + +/** + * Deallocates the encoding data of the given precinct. + */ +void tcd_code_block_dec_deallocate (opj_tcd_precinct_t * p_precinct) +{ + OPJ_UINT32 cblkno , l_nb_code_blocks; + + opj_tcd_cblk_dec_t * l_code_block = p_precinct->cblks.dec; + if + (l_code_block) + { + l_nb_code_blocks = p_precinct->block_size / sizeof(opj_tcd_cblk_dec_t); + for + (cblkno = 0; cblkno < l_nb_code_blocks; ++cblkno) + { + if + (l_code_block->data) + { + opj_free(l_code_block->data); + l_code_block->data = 00; + } + if + (l_code_block->segs) + { + opj_free(l_code_block->segs ); + l_code_block->segs = 00; + } + ++l_code_block; + } + opj_free(p_precinct->cblks.dec); + p_precinct->cblks.dec = 00; + } +} diff --git a/libopenjpeg/tcd.h b/libopenjpeg/tcd.h index e3f93adc..6489ddeb 100644 --- a/libopenjpeg/tcd.h +++ b/libopenjpeg/tcd.h @@ -41,17 +41,31 @@ each other. The functions in TCD.C are used by some function in J2K.C. /** @defgroup TCD TCD - Implementation of a tile coder/decoder */ /*@{*/ +/** +FIXME: documentation +*/ +//typedef struct opj_tcd_seg { +// unsigned char** data; +// int dataindex; +// int numpasses; +// int len; +// int maxpasses; +// int numnewpasses; +// int newlen; +//} opj_tcd_seg_t; + /** FIXME: documentation */ typedef struct opj_tcd_seg { - unsigned char** data; - int dataindex; - int numpasses; - int len; - int maxpasses; - int numnewpasses; - int newlen; + OPJ_BYTE ** data; + OPJ_UINT32 dataindex; + OPJ_UINT32 numpasses; + OPJ_UINT32 real_num_passes; + OPJ_UINT32 len; + OPJ_UINT32 maxpasses; + OPJ_UINT32 numnewpasses; + OPJ_UINT32 newlen; } opj_tcd_seg_t; /** @@ -88,40 +102,75 @@ typedef struct opj_tcd_cblk_enc { int totalpasses; /* total number of passes */ } opj_tcd_cblk_enc_t; +//typedef struct opj_tcd_cblk_dec { +// unsigned char* data; /* Data */ +// opj_tcd_seg_t* segs; /* segments informations */ +// int x0, y0, x1, y1; /* dimension of the code-blocks : left upper corner (x0, y0) right low corner (x1,y1) */ +// int numbps; +// int numlenbits; +// int len; /* length */ +// int numnewpasses; /* number of pass added to the code-blocks */ +// int numsegs; /* number of segments */ +//} opj_tcd_cblk_dec_t; + typedef struct opj_tcd_cblk_dec { - unsigned char* data; /* Data */ + OPJ_BYTE * data; /* Data */ opj_tcd_seg_t* segs; /* segments informations */ - int x0, y0, x1, y1; /* dimension of the code-blocks : left upper corner (x0, y0) right low corner (x1,y1) */ - int numbps; - int numlenbits; - int len; /* length */ - int numnewpasses; /* number of pass added to the code-blocks */ - int numsegs; /* number of segments */ + OPJ_INT32 x0, y0, x1, y1; /* dimension of the code-blocks : left upper corner (x0, y0) right low corner (x1,y1) */ + OPJ_UINT32 numbps; + OPJ_UINT32 numlenbits; + OPJ_UINT32 len; /* length */ + OPJ_UINT32 numnewpasses; /* number of pass added to the code-blocks */ + OPJ_UINT32 numsegs; /* number of segments */ + OPJ_UINT32 real_num_segs; + OPJ_UINT32 m_current_max_segs; } opj_tcd_cblk_dec_t; /** FIXME: documentation */ +//typedef struct opj_tcd_precinct { +// int x0, y0, x1, y1; /* dimension of the precinct : left upper corner (x0, y0) right low corner (x1,y1) */ +// int cw, ch; /* number of precinct in width and heigth */ +// union{ /* code-blocks informations */ +// opj_tcd_cblk_enc_t* enc; +// opj_tcd_cblk_dec_t* dec; +// } cblks; +// opj_tgt_tree_t *incltree; /* inclusion tree */ +// opj_tgt_tree_t *imsbtree; /* IMSB tree */ +//} opj_tcd_precinct_t; + + typedef struct opj_tcd_precinct { - int x0, y0, x1, y1; /* dimension of the precinct : left upper corner (x0, y0) right low corner (x1,y1) */ - int cw, ch; /* number of precinct in width and heigth */ + OPJ_INT32 x0, y0, x1, y1; /* dimension of the precinct : left upper corner (x0, y0) right low corner (x1,y1) */ + OPJ_UINT32 cw, ch; /* number of precinct in width and heigth */ union{ /* code-blocks informations */ opj_tcd_cblk_enc_t* enc; opj_tcd_cblk_dec_t* dec; } cblks; - opj_tgt_tree_t *incltree; /* inclusion tree */ - opj_tgt_tree_t *imsbtree; /* IMSB tree */ + OPJ_UINT32 block_size; /* size taken by cblks (in bytes) */ + struct opj_tgt_tree *incltree; /* inclusion tree */ + struct opj_tgt_tree *imsbtree; /* IMSB tree */ } opj_tcd_precinct_t; /** FIXME: documentation */ +//typedef struct opj_tcd_band { +// int x0, y0, x1, y1; /* dimension of the subband : left upper corner (x0, y0) right low corner (x1,y1) */ +// int bandno; +// opj_tcd_precinct_t *precincts; /* precinct information */ +// int numbps; +// float stepsize; +//} opj_tcd_band_t; + typedef struct opj_tcd_band { - int x0, y0, x1, y1; /* dimension of the subband : left upper corner (x0, y0) right low corner (x1,y1) */ - int bandno; + OPJ_INT32 x0, y0, x1, y1; /* dimension of the subband : left upper corner (x0, y0) right low corner (x1,y1) */ + OPJ_UINT32 bandno; opj_tcd_precinct_t *precincts; /* precinct information */ - int numbps; - float stepsize; + OPJ_UINT32 precincts_data_size; /* size of data taken by precincts */ + OPJ_INT32 numbps; + OPJ_FLOAT32 stepsize; } opj_tcd_band_t; /** @@ -137,14 +186,27 @@ typedef struct opj_tcd_resolution { /** FIXME: documentation */ -typedef struct opj_tcd_tilecomp { - int x0, y0, x1, y1; /* dimension of component : left upper corner (x0, y0) right low corner (x1,y1) */ - int numresolutions; /* number of resolutions level */ +//typedef struct opj_tcd_tilecomp { +// int x0, y0, x1, y1; /* dimension of component : left upper corner (x0, y0) right low corner (x1,y1) */ +// int numresolutions; /* number of resolutions level */ +// opj_tcd_resolution_t *resolutions; /* resolutions information */ +// int *data; /* data of the component */ +// int numpix; /* add fixed_quality */ +//} opj_tcd_tilecomp_t; + +typedef struct opj_tcd_tilecomp +{ + OPJ_INT32 x0, y0, x1, y1; /* dimension of component : left upper corner (x0, y0) right low corner (x1,y1) */ + OPJ_UINT32 numresolutions; /* number of resolutions level */ + OPJ_UINT32 minimum_num_resolutions; /* number of resolutions level to decode (at max)*/ opj_tcd_resolution_t *resolutions; /* resolutions information */ - int *data; /* data of the component */ - int numpix; /* add fixed_quality */ + OPJ_UINT32 resolutions_size; /* size of data for resolutions (in bytes) */ + OPJ_INT32 *data; /* data of the component */ + OPJ_UINT32 data_size; /* size of the data of the component */ + OPJ_INT32 numpix; /* add fixed_quality */ } opj_tcd_tilecomp_t; + /** FIXME: documentation */ @@ -200,6 +262,39 @@ typedef struct opj_tcd { double encoding_time; } opj_tcd_t; + +struct opj_image; +struct opj_cp_v2; +struct opj_tcp_v2; +/** +Tile coder/decoder +*/ +typedef struct opj_tcd_v2 +{ + /** Position of the tilepart flag in Progression order*/ + OPJ_INT32 tp_pos; + /** Tile part number*/ + OPJ_UINT32 tp_num; + /** Current tile part number*/ + OPJ_UINT32 cur_tp_num; + /** Total number of tileparts of the current tile*/ + OPJ_UINT32 cur_totnum_tp; + /** Current Packet iterator number */ + OPJ_UINT32 cur_pino; + /** info on each image tile */ + opj_tcd_image_t *tcd_image; + /** image */ + struct opj_image *image; + /** coding parameters */ + struct opj_cp_v2 *cp; + /** coding/decoding parameters common to all tiles */ + struct opj_tcp_v2 *tcp; + /** current encoded/decoded tile */ + OPJ_UINT32 tcd_tileno; + /** tell if the tcd is a decoder. */ + OPJ_UINT32 m_is_decoder : 1; +} opj_tcd_v2_t; + /** @name Exported functions */ /*@{*/ /* ----------------------------------------------------------------------- */ @@ -214,6 +309,54 @@ Create a new TCD handle @return Returns a new TCD handle if successful returns NULL otherwise */ opj_tcd_t* tcd_create(opj_common_ptr cinfo); + +/** +Create a new TCD handle +@param FIXME +@return Returns a new TCD handle if successful returns NULL otherwise +*/ +opj_tcd_v2_t* tcd_create_v2(opj_bool p_is_decoder); + +/** +Destroy a previously created TCD handle +@param tcd TCD handle to destroy +*/ +void tcd_destroy_v2(opj_tcd_v2_t *tcd); + +/** + * Initialize the tile coder and may reuse some meory. + * @param p_tcd TCD handle. + * @param p_image raw image. + * @param p_cp coding parameters. + * @param p_tile_no current tile index to encode. + * + * @return true if the encoding values could be set (false otherwise). +*/ +opj_bool tcd_init_v2( + opj_tcd_v2_t *p_tcd, + //struct opj_image * p_image, + opj_image_t * p_image, + //struct opj_cp * p_cp + opj_cp_v2_t * p_cp + ); + +/** + * Allocates memory for decoding a specific tile. + * + * @param p_tcd the tile decoder. + * @param p_image the image to decode. + * @param p_cp the decoding parameters. + * @param p_tile_no the index of the tile received in sequence. This not necesseraly lead to the + * tile at index p_tile_no. + * @param p_cstr_info codestream info (if any). + * + * @return true if the remaining data is sufficient.s + */ +opj_bool tcd_init_decode_tile( + opj_tcd_v2_t *p_tcd, + OPJ_UINT32 p_tile_no + ); + /** Destroy a previously created TCD handle @param tcd TCD handle to destroy @@ -278,6 +421,33 @@ Free the memory allocated for decoding void tcd_free_decode(opj_tcd_t *tcd); void tcd_free_decode_tile(opj_tcd_t *tcd, int tileno); + +/** + * Gets the maximum tile size that will be taken by the tile once decoded. + */ +OPJ_UINT32 tcd_get_decoded_tile_size ( + opj_tcd_v2_t *p_tcd + ); + +/** +Decode a tile from a buffer into a raw image +@param tcd TCD handle +@param src Source buffer +@param len Length of source buffer +@param tileno Number that identifies one of the tiles to be decoded +*/ +opj_bool tcd_decode_tile_v2(opj_tcd_v2_t *tcd, OPJ_BYTE *src, OPJ_UINT32 len, OPJ_UINT32 tileno, struct opj_codestream_info *cstr_info); + + +/** + * Copies tile data from the system onto the given memory block. + */ +opj_bool tcd_update_tile_data ( + opj_tcd_v2_t *p_tcd, + OPJ_BYTE * p_dest, + OPJ_UINT32 p_dest_length + ); + /* ----------------------------------------------------------------------- */ /*@}*/ diff --git a/libopenjpeg/tgt.c b/libopenjpeg/tgt.c index a5dbcd3c..57e7ce37 100644 --- a/libopenjpeg/tgt.c +++ b/libopenjpeg/tgt.c @@ -108,6 +108,114 @@ opj_tgt_tree_t *tgt_create(int numleafsh, int numleafsv) { return tree; } +/** + * Reinitialises a tag-tree from an exixting one. + * + * @param p_tree the tree to reinitialize. + * @param p_num_leafs_h the width of the array of leafs of the tree + * @param p_num_leafs_v the height of the array of leafs of the tree + * @return a new tag-tree if successful, NULL otherwise +*/ +opj_tgt_tree_t *tgt_init(opj_tgt_tree_t * p_tree,OPJ_UINT32 p_num_leafs_h, OPJ_UINT32 p_num_leafs_v) +{ + OPJ_INT32 l_nplh[32]; + OPJ_INT32 l_nplv[32]; + opj_tgt_node_t *l_node = 00; + opj_tgt_node_t *l_parent_node = 00; + opj_tgt_node_t *l_parent_node0 = 00; + OPJ_UINT32 i; + OPJ_INT32 j,k; + OPJ_UINT32 l_num_levels; + OPJ_UINT32 n; + OPJ_UINT32 l_node_size; + + if + (! p_tree) + { + return 00; + } + if + ((p_tree->numleafsh != p_num_leafs_h) || (p_tree->numleafsv != p_num_leafs_v)) + { + p_tree->numleafsh = p_num_leafs_h; + p_tree->numleafsv = p_num_leafs_v; + + l_num_levels = 0; + l_nplh[0] = p_num_leafs_h; + l_nplv[0] = p_num_leafs_v; + p_tree->numnodes = 0; + do + { + n = l_nplh[l_num_levels] * l_nplv[l_num_levels]; + l_nplh[l_num_levels + 1] = (l_nplh[l_num_levels] + 1) / 2; + l_nplv[l_num_levels + 1] = (l_nplv[l_num_levels] + 1) / 2; + p_tree->numnodes += n; + ++l_num_levels; + } + while (n > 1); + + /* ADD */ + if + (p_tree->numnodes == 0) + { + tgt_destroy(p_tree); + return 00; + } + l_node_size = p_tree->numnodes * sizeof(opj_tgt_node_t); + if + (l_node_size > p_tree->nodes_size) + { + p_tree->nodes = (opj_tgt_node_t*) opj_realloc(p_tree->nodes, l_node_size); + if + (! p_tree->nodes) + { + tgt_destroy(p_tree); + return 00; + } + memset(((char *) p_tree->nodes) + p_tree->nodes_size, 0 , l_node_size - p_tree->nodes_size); + p_tree->nodes_size = l_node_size; + } + l_node = p_tree->nodes; + l_parent_node = &p_tree->nodes[p_tree->numleafsh * p_tree->numleafsv]; + l_parent_node0 = l_parent_node; + + for + (i = 0; i < l_num_levels - 1; ++i) + { + for + (j = 0; j < l_nplv[i]; ++j) + { + k = l_nplh[i]; + while + (--k >= 0) + { + l_node->parent = l_parent_node; + ++l_node; + if (--k >= 0) + { + l_node->parent = l_parent_node; + ++l_node; + } + ++l_parent_node; + } + if ((j & 1) || j == l_nplv[i] - 1) + { + l_parent_node0 = l_parent_node; + } + else + { + l_parent_node = l_parent_node0; + l_parent_node0 += l_nplh[i]; + } + } + } + l_node->parent = 0; + } + tgt_reset(p_tree); + + return p_tree; +} + void tgt_destroy(opj_tgt_tree_t *tree) { opj_free(tree->nodes); opj_free(tree); diff --git a/libopenjpeg/tgt.h b/libopenjpeg/tgt.h index c08c8da0..8c1b112f 100644 --- a/libopenjpeg/tgt.h +++ b/libopenjpeg/tgt.h @@ -52,16 +52,29 @@ typedef struct opj_tgt_node { int known; } opj_tgt_node_t; +///** OPJ_V1 +//Tag tree +//*/ +//typedef struct opj_tgt_tree { +// int numleafsh; +// int numleafsv; +// int numnodes; +// opj_tgt_node_t *nodes; +//} opj_tgt_tree_t; + /** Tag tree */ -typedef struct opj_tgt_tree { - int numleafsh; - int numleafsv; - int numnodes; - opj_tgt_node_t *nodes; +typedef struct opj_tgt_tree +{ + OPJ_UINT32 numleafsh; + OPJ_UINT32 numleafsv; + OPJ_UINT32 numnodes; + opj_tgt_node_t *nodes; + OPJ_UINT32 nodes_size; /* maximum size taken by nodes */ } opj_tgt_tree_t; + /** @name Exported functions */ /*@{*/ /* ----------------------------------------------------------------------- */ @@ -72,6 +85,18 @@ Create a tag-tree @return Returns a new tag-tree if successful, returns NULL otherwise */ opj_tgt_tree_t *tgt_create(int numleafsh, int numleafsv); + +/** + * Reinitialises a tag-tree from an exixting one. + * + * @param p_tree the tree to reinitialize. + * @param p_num_leafs_h the width of the array of leafs of the tree + * @param p_num_leafs_v the height of the array of leafs of the tree + * @return a new tag-tree if successful, NULL otherwise +*/ +opj_tgt_tree_t *tgt_init(opj_tgt_tree_t * p_tree,OPJ_UINT32 p_num_leafs_h, OPJ_UINT32 p_num_leafs_v); + + /** Destroy a tag-tree, liberating memory @param tree Tag-tree to destroy diff --git a/opj_configh.cmake.in b/opj_configh.cmake.in index c05d8d55..6da59ddd 100644 --- a/opj_configh.cmake.in +++ b/opj_configh.cmake.in @@ -20,3 +20,9 @@ #cmakedefine HAVE_LCMS1_H @HAVE_LCMS1_H@ #cmakedefine HAVE_LCMS2_H @HAVE_LCMS2_H@ +#cmakedefine CMAKE_WORDS_BIGENDIAN +#ifdef CMAKE_WORDS_BIGENDIAN + #define OPJ_BIG_ENDIAN +#else + #define OPJ_LITTLE_ENDIAN +#endif