diff options
| author | Antonin Descampe <antonin@gmail.com> | 2008-07-31 18:47:41 +0000 |
|---|---|---|
| committer | Antonin Descampe <antonin@gmail.com> | 2008-07-31 18:47:41 +0000 |
| commit | 7caaea18b728ead4e45226aafc09dba01e514a2d (patch) | |
| tree | 1d5d19df20b82cee63a7de94fc8e04e8426cb7c7 /libopenjpeg | |
| parent | 8407e057c9e10c8fc2b5f4be56e603fae3f9063d (diff) | |
Deleting obsolete files and directories, adding v2-specific files and directories, updating existing files to v2. See README.v2 for more info
Diffstat (limited to 'libopenjpeg')
48 files changed, 20148 insertions, 5870 deletions
diff --git a/libopenjpeg/CMakeLists.txt b/libopenjpeg/CMakeLists.txt index 2814ad40..e310e1bb 100644 --- a/libopenjpeg/CMakeLists.txt +++ b/libopenjpeg/CMakeLists.txt @@ -1,6 +1,7 @@ INCLUDE_REGULAR_EXPRESSION("^.*$") # Defines the source code for the library SET(OPENJPEG_SRCS + tcd.c bio.c cio.c dwt.c @@ -16,9 +17,33 @@ SET(OPENJPEG_SRCS pi.c raw.c t1.c - t2.c - tcd.c tgt.c + profile.c + invert.c + function_list.c + t2.c + bio.h + cio.h + dwt.h + event.h + image.h + j2k.h + j2k_lib.h + jp2.h + jpt.h + mct.h + mqc.h + openjpeg.h + pi.h + int.h + raw.h + t1.h + t2.h + tcd.h + tgt.h + profile.h + invert.h + function_list.h ) # Pass proper definition to preprocessor to generate shared lib @@ -30,6 +55,10 @@ IF(WIN32) ENDIF(BUILD_SHARED_LIBS) ENDIF(WIN32) +IF(ENABLE_PROFILING) + ADD_DEFINITIONS(-D_PROFILE) +ENDIF(ENABLE_PROFILING) + # Create the library ADD_LIBRARY(${OPENJPEG_LIBRARY_NAME} ${OPENJPEG_SRCS}) SET_TARGET_PROPERTIES(${OPENJPEG_LIBRARY_NAME} PROPERTIES diff --git a/libopenjpeg/bio.c b/libopenjpeg/bio.c index 4c02f464..78fefa79 100644 --- a/libopenjpeg/bio.c +++ b/libopenjpeg/bio.c @@ -5,6 +5,7 @@ * Copyright (c) 2002-2003, Yannick Verschueren * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,7 +30,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "opj_includes.h" +#include "bio.h" +#include "opj_malloc.h" /** @defgroup BIO BIO - Individual bit input-output stream */ /*@{*/ @@ -42,25 +44,25 @@ Write a bit @param bio BIO handle @param b Bit to write (0 or 1) */ -static void bio_putbit(opj_bio_t *bio, int b); +static void bio_putbit(opj_bio_t *bio, OPJ_UINT32 b); /** Read a bit @param bio BIO handle @return Returns the read bit */ -static int bio_getbit(opj_bio_t *bio); +static OPJ_UINT32 bio_getbit(opj_bio_t *bio); /** Write a byte @param bio BIO handle @return Returns 0 if successful, returns 1 otherwise */ -static int bio_byteout(opj_bio_t *bio); +static bool bio_byteout(opj_bio_t *bio); /** Read a byte @param bio BIO handle @return Returns 0 if successful, returns 1 otherwise */ -static int bio_bytein(opj_bio_t *bio); +static bool bio_bytein(opj_bio_t *bio); /*@}*/ @@ -72,27 +74,27 @@ static int bio_bytein(opj_bio_t *bio); ========================================================== */ -static int bio_byteout(opj_bio_t *bio) { +static bool bio_byteout(opj_bio_t *bio) { bio->buf = (bio->buf << 8) & 0xffff; bio->ct = bio->buf == 0xff00 ? 7 : 8; if (bio->bp >= bio->end) { - return 1; + return true; } *bio->bp++ = bio->buf >> 8; - return 0; + return false; } -static int bio_bytein(opj_bio_t *bio) { +static bool bio_bytein(opj_bio_t *bio) { bio->buf = (bio->buf << 8) & 0xffff; bio->ct = bio->buf == 0xff00 ? 7 : 8; if (bio->bp >= bio->end) { - return 1; + return true; } bio->buf |= *bio->bp++; - return 0; + return false; } -static void bio_putbit(opj_bio_t *bio, int b) { +static void bio_putbit(opj_bio_t *bio, OPJ_UINT32 b) { if (bio->ct == 0) { bio_byteout(bio); } @@ -100,7 +102,7 @@ static void bio_putbit(opj_bio_t *bio, int b) { bio->buf |= b << bio->ct; } -static int bio_getbit(opj_bio_t *bio) { +static OPJ_UINT32 bio_getbit(opj_bio_t *bio) { if (bio->ct == 0) { bio_bytein(bio); } @@ -125,11 +127,11 @@ void bio_destroy(opj_bio_t *bio) { } } -int bio_numbytes(opj_bio_t *bio) { +OPJ_UINT32 bio_numbytes(opj_bio_t *bio) { return (bio->bp - bio->start); } -void bio_init_enc(opj_bio_t *bio, unsigned char *bp, int len) { +void bio_init_enc(opj_bio_t *bio, OPJ_BYTE *bp, OPJ_UINT32 len) { bio->start = bp; bio->end = bp + len; bio->bp = bp; @@ -137,7 +139,7 @@ void bio_init_enc(opj_bio_t *bio, unsigned char *bp, int len) { bio->ct = 8; } -void bio_init_dec(opj_bio_t *bio, unsigned char *bp, int len) { +void bio_init_dec(opj_bio_t *bio, OPJ_BYTE *bp, OPJ_UINT32 len) { bio->start = bp; bio->end = bp + len; bio->bp = bp; @@ -145,43 +147,43 @@ void bio_init_dec(opj_bio_t *bio, unsigned char *bp, int len) { bio->ct = 0; } -void bio_write(opj_bio_t *bio, int v, int n) { - int i; - for (i = n - 1; i >= 0; i--) { +void bio_write(opj_bio_t *bio, OPJ_UINT32 v, OPJ_UINT32 n) { + OPJ_UINT32 i; + for (i = n - 1; i != -1 ; --i) { bio_putbit(bio, (v >> i) & 1); } } -int bio_read(opj_bio_t *bio, int n) { - int i, v; +OPJ_UINT32 bio_read(opj_bio_t *bio, OPJ_UINT32 n) { + OPJ_UINT32 i, v; v = 0; - for (i = n - 1; i >= 0; i--) { + for (i = n - 1; i != -1 ; --i) { v += bio_getbit(bio) << i; } return v; } -int bio_flush(opj_bio_t *bio) { +bool bio_flush(opj_bio_t *bio) { bio->ct = 0; if (bio_byteout(bio)) { - return 1; + return true; } if (bio->ct == 7) { bio->ct = 0; if (bio_byteout(bio)) { - return 1; + return true; } } - return 0; + return false; } -int bio_inalign(opj_bio_t *bio) { +bool bio_inalign(opj_bio_t *bio) { bio->ct = 0; if ((bio->buf & 0xff) == 0xff) { if (bio_bytein(bio)) { - return 1; + return true; } bio->ct = 0; } - return 0; + return false; } diff --git a/libopenjpeg/bio.h b/libopenjpeg/bio.h index 764d7cb2..cc25aa39 100644 --- a/libopenjpeg/bio.h +++ b/libopenjpeg/bio.h @@ -5,6 +5,7 @@ * Copyright (c) 2002-2003, Yannick Verschueren * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,7 +38,7 @@ The functions in BIO.C have for goal to realize an individual bit input - output. */ - +#include "openjpeg.h" /** @defgroup BIO BIO - Individual bit input-output stream */ /*@{*/ @@ -46,15 +47,15 @@ Individual bit input-output stream (BIO) */ typedef struct opj_bio { /** pointer to the start of the buffer */ - unsigned char *start; + OPJ_BYTE *start; /** pointer to the end of the buffer */ - unsigned char *end; + OPJ_BYTE *end; /** pointer to the present position in the buffer */ - unsigned char *bp; + OPJ_BYTE *bp; /** temporary place where each byte is read or written */ - unsigned int buf; + OPJ_UINT32 buf; /** coder : number of bits free to write. decoder : number of bits read */ - int ct; + OPJ_UINT32 ct; } opj_bio_t; /** @name Exported functions */ @@ -75,47 +76,47 @@ Number of bytes written. @param bio BIO handle @return Returns the number of bytes written */ -int bio_numbytes(opj_bio_t *bio); +OPJ_UINT32 bio_numbytes(opj_bio_t *bio); /** Init encoder @param bio BIO handle @param bp Output buffer @param len Output buffer length */ -void bio_init_enc(opj_bio_t *bio, unsigned char *bp, int len); +void bio_init_enc(opj_bio_t *bio, OPJ_BYTE *bp, OPJ_UINT32 len); /** Init decoder @param bio BIO handle @param bp Input buffer @param len Input buffer length */ -void bio_init_dec(opj_bio_t *bio, unsigned char *bp, int len); +void bio_init_dec(opj_bio_t *bio, OPJ_BYTE *bp, OPJ_UINT32 len); /** Write bits @param bio BIO handle @param v Value of bits @param n Number of bits to write */ -void bio_write(opj_bio_t *bio, int v, int n); +void bio_write(opj_bio_t *bio, OPJ_UINT32 v, OPJ_UINT32 n); /** Read bits @param bio BIO handle @param n Number of bits to read @return Returns the corresponding read number */ -int bio_read(opj_bio_t *bio, int n); +OPJ_UINT32 bio_read(opj_bio_t *bio, OPJ_UINT32 n); /** Flush bits @param bio BIO handle @return Returns 1 if successful, returns 0 otherwise */ -int bio_flush(opj_bio_t *bio); +bool bio_flush(opj_bio_t *bio); /** Passes the ending bits (coming from flushing) @param bio BIO handle @return Returns 1 if successful, returns 0 otherwise */ -int bio_inalign(opj_bio_t *bio); +bool bio_inalign(opj_bio_t *bio); /* ----------------------------------------------------------------------- */ /*@}*/ diff --git a/libopenjpeg/cio.c b/libopenjpeg/cio.c index 2ac262a1..05c7101c 100644 --- a/libopenjpeg/cio.c +++ b/libopenjpeg/cio.c @@ -5,6 +5,7 @@ * Copyright (c) 2002-2003, Yannick Verschueren * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,162 +30,790 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include "cio.h" #include "opj_includes.h" +#include "opj_malloc.h" +#include "event.h" /* ----------------------------------------------------------------------- */ -opj_cio_t* OPJ_CALLCONV opj_cio_open(opj_common_ptr cinfo, unsigned char *buffer, int length) { - opj_cp_t *cp = NULL; - opj_cio_t *cio = (opj_cio_t*)opj_malloc(sizeof(opj_cio_t)); - if(!cio) return NULL; - cio->cinfo = cinfo; - if(buffer && length) { - /* wrap a user buffer containing the encoded image */ - cio->openmode = OPJ_STREAM_READ; - cio->buffer = buffer; - cio->length = length; - } - else if(!buffer && !length && cinfo) { - /* allocate a buffer for the encoded image */ - cio->openmode = OPJ_STREAM_WRITE; - switch(cinfo->codec_format) { - case CODEC_J2K: - cp = ((opj_j2k_t*)cinfo->j2k_handle)->cp; - break; - case CODEC_JP2: - cp = ((opj_jp2_t*)cinfo->jp2_handle)->j2k->cp; - break; - default: - opj_free(cio); - return NULL; - } - cio->length = (unsigned int) (0.1625 * cp->img_size + 2000); /* 0.1625 = 1.3/8 and 2000 bytes as a minimum for headers */ - cio->buffer = (unsigned char *)opj_malloc(cio->length); - if(!cio->buffer) { - opj_event_msg(cio->cinfo, EVT_ERROR, "Error allocating memory for compressed bitstream\n"); - opj_free(cio); - return NULL; - } + +/** + * 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<p_nb_bytes;++i) + { + *(p_buffer++) = *(l_data_ptr--); } - else { - opj_free(cio); - return NULL; +} + +/** + * 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) +{ + OPJ_BYTE * l_data_ptr = ((OPJ_BYTE *) p_value); + assert(p_nb_bytes > 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;i<p_nb_bytes;++i) + { + *(l_data_ptr--) = *(p_buffer++); } +} - /* Initialize byte IO */ - cio->start = cio->buffer; - cio->end = cio->buffer + cio->length; - cio->bp = cio->buffer; +/** + * 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 + * @return the number of bytes written or -1 if an error occured + */ +void opj_write_double_BE(OPJ_BYTE * p_buffer, OPJ_FLOAT64 p_value) +{ + const OPJ_BYTE * l_data_ptr = ((const OPJ_BYTE *) &p_value); + memcpy(p_buffer,l_data_ptr,sizeof(OPJ_FLOAT64)); +} - return cio; +/** + * 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) +{ + const OPJ_BYTE * l_data_ptr = ((const OPJ_BYTE *) &p_value) + sizeof(OPJ_FLOAT64) - 1; + OPJ_UINT32 i; + for + (i=0;i<sizeof(OPJ_FLOAT64);++i) + { + *(p_buffer++) = *(l_data_ptr--); + } } -void OPJ_CALLCONV opj_cio_close(opj_cio_t *cio) { - if(cio) { - if(cio->openmode == OPJ_STREAM_WRITE) { - /* destroy the allocated buffer */ - opj_free(cio->buffer); - } - /* destroy the cio */ - opj_free(cio); +/** + * 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) +{ + OPJ_BYTE * l_data_ptr = ((OPJ_BYTE *) p_value); + memcpy(l_data_ptr,p_buffer,sizeof(OPJ_FLOAT64)); +} + + +/** + * 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) +{ + OPJ_BYTE * l_data_ptr = ((OPJ_BYTE *) p_value) + sizeof(OPJ_FLOAT64)-1; + OPJ_UINT32 i; + for + (i=0;i<sizeof(OPJ_FLOAT64);++i) + { + *(l_data_ptr--) = *(p_buffer++); } } +/** + * 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 + * @return the number of bytes written or -1 if an error occured + */ +void opj_write_float_BE(OPJ_BYTE * p_buffer, OPJ_FLOAT32 p_value) +{ + const OPJ_BYTE * l_data_ptr = ((const OPJ_BYTE *) &p_value); + memcpy(p_buffer,l_data_ptr,sizeof(OPJ_FLOAT32)); +} -/* ----------------------------------------------------------------------- */ +/** + * 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) +{ + const OPJ_BYTE * l_data_ptr = ((const OPJ_BYTE *) &p_value) + sizeof(OPJ_FLOAT32) - 1; + OPJ_UINT32 i; + for + (i=0;i<sizeof(OPJ_FLOAT32);++i) + { + *(p_buffer++) = *(l_data_ptr--); + } +} -/* - * Get position in byte stream. +/** + * 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. */ -int OPJ_CALLCONV cio_tell(opj_cio_t *cio) { - return cio->bp - cio->start; +void opj_read_float_BE(const OPJ_BYTE * p_buffer, OPJ_FLOAT32 * p_value) +{ + OPJ_BYTE * l_data_ptr = ((OPJ_BYTE *) p_value); + memcpy(l_data_ptr,p_buffer,sizeof(OPJ_FLOAT32)); } -/* - * Set position in byte stream. - * - * pos : position, in number of bytes, from the beginning of the stream + +/** + * 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_CALLCONV cio_seek(opj_cio_t *cio, int pos) { - cio->bp = cio->start + pos; +void opj_read_float_LE(const OPJ_BYTE * p_buffer, OPJ_FLOAT32 * p_value) +{ + OPJ_BYTE * l_data_ptr = ((OPJ_BYTE *) p_value) + sizeof(OPJ_FLOAT32)-1; + OPJ_UINT32 i; + for + (i=0;i<sizeof(OPJ_FLOAT32);++i) + { + *(l_data_ptr--) = *(p_buffer++); + } } -/* - * Number of bytes left before the end of the 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_stream_create(OPJ_UINT32 p_size,bool l_is_input) +{ + opj_stream_private_t * l_stream = 00; + l_stream = (opj_stream_private_t*) opj_malloc(sizeof(opj_stream_private_t)); + if + (! l_stream) + { + return 00; + } + memset(l_stream,0,sizeof(opj_stream_private_t)); + l_stream->m_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_stream_default_create(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. */ -int cio_numbytesleft(opj_cio_t *cio) { - return cio->end - cio->bp; +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); + } + } -/* - * Get pointer to the current position in the 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; + } + + while + (true) + { + // 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 + opj_event_msg(p_event_mgr, EVT_INFO, "Stream reached its end !\n"); + 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 + opj_event_msg(p_event_mgr, EVT_INFO, "Stream reached its end !\n"); + 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. */ -unsigned char *cio_getbp(opj_cio_t *cio) { - return cio->bp; +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 + (true) + { + 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; + } + } + } -/* - * Write a byte. +/** + * 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. */ -bool cio_byteout(opj_cio_t *cio, unsigned char v) { - if (cio->bp >= cio->end) { - opj_event_msg(cio->cinfo, EVT_ERROR, "write error\n"); - return false; +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; + opj_event_msg(p_event_mgr, EVT_INFO, "Error on writting stream!\n"); + return false; + } + p_stream->m_current_data += l_current_write_nb_bytes; + p_stream->m_bytes_in_buffer -= l_current_write_nb_bytes; } - *cio->bp++ = v; + p_stream->m_current_data = p_stream->m_stored_data; return true; } -/* - * Read a byte. +/** + * 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. */ -unsigned char cio_bytein(opj_cio_t *cio) { - if (cio->bp >= cio->end) { - opj_event_msg(cio->cinfo, EVT_ERROR, "read error: passed the end of the codestream (start = %d, current = %d, end = %d\n", cio->start, cio->bp, cio->end); - return 0; +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; } - return *cio->bp++; + + // 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) + { + opj_event_msg(p_event_mgr, EVT_INFO, "Stream reached its end !\n"); + 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; } -/* - * Write some bytes. - * - * v : value to write - * n : number of bytes to write +/** + * 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. */ -unsigned int cio_write(opj_cio_t *cio, unsigned int v, int n) { - int i; - for (i = n - 1; i >= 0; i--) { - if( !cio_byteout(cio, (unsigned char) ((v >> (i << 3)) & 0xff)) ) - return 0; +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) +{ + 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; } - return n; + + // 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) + { + opj_event_msg(p_event_mgr, EVT_INFO, "Stream error!\n"); + 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; } -/* - * Read some bytes. - * - * n : number of bytes to read - * - * return : value of the n bytes read +/** + * 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) +{ + 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. */ -unsigned int cio_read(opj_cio_t *cio, int n) { - int i; - unsigned int v; - v = 0; - for (i = n - 1; i >= 0; i--) { - v += cio_bytein(cio) << (i << 3); +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. + */ +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 false; + } + else + { + // reset stream status + p_stream->m_status &= (~opj_stream_e_end); + p_stream->m_byte_offset = p_size; + } - return v; + return true; } -/* - * Skip some bytes. - * - * n : number of bytes to skip +/** + * 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. */ -void cio_skip(opj_cio_t *cio, int n) { - cio->bp += n; +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 false; + } + + 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 false; + } + else + { + p_stream->m_byte_offset = p_size; + } + return true; +} + + +/** + * 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. + */ +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. + */ +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; +} + +bool opj_stream_default_seek (OPJ_SIZE_T p_nb_bytes, void * p_user_data) +{ + return false; } diff --git a/libopenjpeg/cio.h b/libopenjpeg/cio.h index 580bf9c0..12055ff0 100644 --- a/libopenjpeg/cio.h +++ b/libopenjpeg/cio.h @@ -5,6 +5,7 @@ * Copyright (c) 2002-2003, Yannick Verschueren * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -41,42 +42,314 @@ The functions in CIO.C have for goal to realize a byte input / output process. /** @defgroup CIO CIO - byte input-output stream */ /*@{*/ +#include "openjpeg.h" +#include "opj_configure.h" +struct opj_event_mgr; /** @name Exported functions (see also openjpeg.h) */ /*@{*/ /* ----------------------------------------------------------------------- */ + +#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 ; + /** -Number of bytes left before the end of the stream -@param cio CIO handle -@return Returns the number of bytes before the end of the stream +Byte input-output stream. */ -int cio_numbytesleft(opj_cio_t *cio); +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 *); + + 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; + + /** -Get pointer to the current position in the stream -@param cio CIO handle -@return Returns a pointer to the current position + * 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 */ -unsigned char *cio_getbp(opj_cio_t *cio); +void opj_write_bytes_BE (OPJ_BYTE * p_buffer, OPJ_UINT32 p_value, OPJ_UINT32 p_nb_bytes); + /** -Write some bytes -@param cio CIO handle -@param v Value to write -@param n Number of bytes to write -@return Returns the number of bytes written or 0 if an error occured -*/ -unsigned int cio_write(opj_cio_t *cio, unsigned int v, int n); + * 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); + /** -Read some bytes -@param cio CIO handle -@param n Number of bytes to read -@return Returns the value of the n bytes read + * 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 */ -unsigned int cio_read(opj_cio_t *cio, int n); +void opj_write_bytes_LE (OPJ_BYTE * p_buffer, OPJ_UINT32 p_value, OPJ_UINT32 p_nb_bytes); + /** -Skip some bytes -@param cio CIO handle -@param n Number of bytes to skip -*/ -void cio_skip(opj_cio_t *cio, int n); + * 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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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); +bool opj_stream_default_seek (OPJ_SIZE_T p_nb_bytes, void * p_user_data); + /* ----------------------------------------------------------------------- */ /*@}*/ diff --git a/libopenjpeg/dwt.c b/libopenjpeg/dwt.c index 78d18d17..a6ffd180 100644 --- a/libopenjpeg/dwt.c +++ b/libopenjpeg/dwt.c @@ -7,6 +7,7 @@ * Copyright (c) 2005, Herve Drolon, FreeImage Team * Copyright (c) 2007, Jonathan Ballard <dzonatas@dzonux.net> * Copyright (c) 2007, Callum Lerwick <seg@haxxed.com> + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,7 +36,12 @@ #include <xmmintrin.h> #endif -#include "opj_includes.h" +#include "dwt.h" +#include "j2k.h" +#include "tcd.h" +#include "fix.h" +#include "opj_malloc.h" +#include "int.h" /** @defgroup DWT DWT - Implementation of a discrete wavelet transform */ /*@{*/ @@ -47,31 +53,31 @@ /*@{*/ typedef struct dwt_local { - int* mem; - int dn; - int sn; - int cas; + OPJ_INT32* mem; + OPJ_INT32 dn; + OPJ_INT32 sn; + OPJ_INT32 cas; } dwt_t; typedef union { - float f[4]; + OPJ_FLOAT32 f[4]; } v4; typedef struct v4dwt_local { v4* wavelet ; - int dn ; - int sn ; - int cas ; + OPJ_INT32 dn ; + OPJ_INT32 sn ; + OPJ_INT32 cas ; } v4dwt_t ; -static const float dwt_alpha = 1.586134342f; // 12994 -static const float dwt_beta = 0.052980118f; // 434 -static const float dwt_gamma = -0.882911075f; // -7233 -static const float dwt_delta = -0.443506852f; // -3633 +static const OPJ_FLOAT32 dwt_alpha = 1.586134342f; // 12994 +static const OPJ_FLOAT32 dwt_beta = 0.052980118f; // 434 +static const OPJ_FLOAT32 dwt_gamma = -0.882911075f; // -7233 +static const OPJ_FLOAT32 delta = -0.443506852f; // -3633 -static const float K = 1.230174105f; // 10078 +static const OPJ_FLOAT32 K = 1.230174105f; // 10078 /* FIXME: What is this constant? */ -static const float c13318 = 1.625732422f; +static const OPJ_FLOAT32 c13318 = 1.625732422f; /*@}*/ @@ -86,23 +92,23 @@ typedef void (*DWT1DFN)(dwt_t* v); /** Forward lazy transform (horizontal) */ -static void dwt_deinterleave_h(int *a, int *b, int dn, int sn, int cas); +static void dwt_deinterleave_h(OPJ_INT32 *a, OPJ_INT32 *b, OPJ_INT32 dn, OPJ_INT32 sn, OPJ_INT32 cas); /** Forward lazy transform (vertical) */ -static void dwt_deinterleave_v(int *a, int *b, int dn, int sn, int x, int cas); +static void dwt_deinterleave_v(OPJ_INT32 *a, OPJ_INT32 *b, OPJ_INT32 dn, OPJ_INT32 sn, OPJ_INT32 x, OPJ_INT32 cas); /** Inverse lazy transform (horizontal) */ -static void dwt_interleave_h(dwt_t* h, int *a); +static void dwt_interleave_h(dwt_t* h, OPJ_INT32 *a); /** Inverse lazy transform (vertical) */ -static void dwt_interleave_v(dwt_t* v, int *a, int x); +static void dwt_interleave_v(dwt_t* v, OPJ_INT32 *a, OPJ_INT32 x); /** Forward 5-3 wavelet transform in 1-D */ -static void dwt_encode_1(int *a, int dn, int sn, int cas); +static void dwt_encode_1(OPJ_INT32 *a, OPJ_INT32 dn, OPJ_INT32 sn, OPJ_INT32 cas); /** Inverse 5-3 wavelet transform in 1-D */ @@ -110,16 +116,19 @@ static void dwt_decode_1(dwt_t *v); /** Forward 9-7 wavelet transform in 1-D */ -static void dwt_encode_1_real(int *a, int dn, int sn, int cas); +static void dwt_encode_1_real(OPJ_INT32 *a, OPJ_INT32 dn, OPJ_INT32 sn, OPJ_INT32 cas); /** Explicit calculation of the Quantization Stepsizes */ -static void dwt_encode_stepsize(int stepsize, int numbps, opj_stepsize_t *bandno_stepsize); +static void dwt_encode_stepsize(OPJ_INT32 stepsize, OPJ_INT32 numbps, opj_stepsize_t *bandno_stepsize); /** Inverse wavelet transform in 2-D. */ -static void dwt_decode_tile(opj_tcd_tilecomp_t* tilec, int i, DWT1DFN fn); +static bool dwt_decode_tile(opj_tcd_tilecomp_t* tilec, OPJ_UINT32 i, DWT1DFN fn); +static OPJ_UINT32 dwt_max_resolution(opj_tcd_resolution_t* restrict r, OPJ_UINT32 i); + +static INLINE bool dwt_encode_procedure(opj_tcd_tilecomp_t * tilec,void (*p_function)(OPJ_INT32 *, OPJ_INT32,OPJ_INT32,OPJ_INT32) ); /*@}*/ /*@}*/ @@ -135,7 +144,7 @@ static void dwt_decode_tile(opj_tcd_tilecomp_t* tilec, int i, DWT1DFN fn); /* <summary> */ /* This table contains the norms of the 5-3 wavelets for different bands. */ /* </summary> */ -static const double dwt_norms[4][10] = { +static const OPJ_FLOAT64 dwt_norms[4][10] = { {1.000, 1.500, 2.750, 5.375, 10.68, 21.34, 42.67, 85.33, 170.7, 341.3}, {1.038, 1.592, 2.919, 5.703, 11.33, 22.64, 45.25, 90.48, 180.9}, {1.038, 1.592, 2.919, 5.703, 11.33, 22.64, 45.25, 90.48, 180.9}, @@ -145,7 +154,7 @@ static const double dwt_norms[4][10] = { /* <summary> */ /* This table contains the norms of the 9-7 wavelets for different bands. */ /* </summary> */ -static const double dwt_norms_real[4][10] = { +static const OPJ_FLOAT64 dwt_norms_real[4][10] = { {1.000, 1.965, 4.177, 8.403, 16.90, 33.84, 67.69, 135.3, 270.6, 540.9}, {2.022, 3.989, 8.355, 17.04, 34.27, 68.63, 137.3, 274.6, 549.0}, {2.022, 3.989, 8.355, 17.04, 34.27, 68.63, 137.3, 274.6, 549.0}, @@ -161,48 +170,88 @@ static const double dwt_norms_real[4][10] = { /* <summary> */ /* Forward lazy transform (horizontal). */ /* </summary> */ -static void dwt_deinterleave_h(int *a, int *b, int dn, int sn, int cas) { - int i; - for (i=0; i<sn; i++) b[i]=a[2*i+cas]; - for (i=0; i<dn; i++) b[sn+i]=a[(2*i+1-cas)]; +static void dwt_deinterleave_h(OPJ_INT32 *a, OPJ_INT32 *b, OPJ_INT32 dn, OPJ_INT32 sn, OPJ_INT32 cas) { + OPJ_INT32 i; + + OPJ_INT32 * l_dest = b; + OPJ_INT32 * l_src = a+cas; + for + (i=0; i<sn; ++i) + { + *l_dest++ = *l_src; + l_src += 2; + } + l_dest = b + sn; + l_src = a + 1 - cas; + for + (i=0; i<dn; ++i) + { + *l_dest++=*l_src; + l_src += 2; + } } /* <summary> */ /* Forward lazy transform (vertical). */ /* </summary> */ -static void dwt_deinterleave_v(int *a, int *b, int dn, int sn, int x, int cas) { - int i; - for (i=0; i<sn; i++) b[i*x]=a[2*i+cas]; - for (i=0; i<dn; i++) b[(sn+i)*x]=a[(2*i+1-cas)]; +static void dwt_deinterleave_v(OPJ_INT32 *a, OPJ_INT32 *b, OPJ_INT32 dn, OPJ_INT32 sn, OPJ_INT32 x, OPJ_INT32 cas) { + OPJ_INT32 i = sn; + OPJ_INT32 * l_dest = b; + OPJ_INT32 * l_src = a+cas; + + while + (i--) + { + *l_dest = *l_src; + l_dest += x; + l_src += 2; + /* b[i*x]=a[2*i+cas]; */ + } + l_dest = b + sn * x; + l_src = a + 1 - cas; + + i = dn; + while + (i--) + { + *l_dest = *l_src; + l_dest += x; + l_src += 2; + /*b[(sn+i)*x]=a[(2*i+1-cas)];*/ + } } /* <summary> */ /* Inverse lazy transform (horizontal). */ /* </summary> */ -static void dwt_interleave_h(dwt_t* h, int *a) { - int *ai = a; - int *bi = h->mem + h->cas; - int i = h->sn; - while( i-- ) { - *bi = *(ai++); - bi += 2; +static void dwt_interleave_h(dwt_t* h, OPJ_INT32 *a) { + OPJ_INT32 *ai = a; + OPJ_INT32 *bi = h->mem + h->cas; + OPJ_INT32 i = h->sn; + while + ( i-- ) + { + *bi = *(ai++); + bi += 2; } ai = a + h->sn; bi = h->mem + 1 - h->cas; i = h->dn ; - while( i-- ) { - *bi = *(ai++); - bi += 2; + while + ( i-- ) + { + *bi = *(ai++); + bi += 2; } } /* <summary> */ /* Inverse lazy transform (vertical). */ /* </summary> */ -static void dwt_interleave_v(dwt_t* v, int *a, int x) { - int *ai = a; - int *bi = v->mem + v->cas; - int i = v->sn; +static void dwt_interleave_v(dwt_t* v, OPJ_INT32 *a, OPJ_INT32 x) { + OPJ_INT32 *ai = a; + OPJ_INT32 *bi = v->mem + v->cas; + OPJ_INT32 i = v->sn; while( i-- ) { *bi = *ai; bi += 2; @@ -222,8 +271,8 @@ static void dwt_interleave_v(dwt_t* v, int *a, int x) { /* <summary> */ /* Forward 5-3 wavelet transform in 1-D. */ /* </summary> */ -static void dwt_encode_1(int *a, int dn, int sn, int cas) { - int i; +static void dwt_encode_1(OPJ_INT32 *a, OPJ_INT32 dn, OPJ_INT32 sn, OPJ_INT32 cas) { + OPJ_INT32 i; if (!cas) { if ((dn > 0) || (sn > 1)) { /* NEW : CASE ONE ELEMENT */ @@ -243,8 +292,8 @@ static void dwt_encode_1(int *a, int dn, int sn, int cas) { /* <summary> */ /* Inverse 5-3 wavelet transform in 1-D. */ /* </summary> */ -static void dwt_decode_1_(int *a, int dn, int sn, int cas) { - int i; +static void dwt_decode_1_(OPJ_INT32 *a, OPJ_INT32 dn, OPJ_INT32 sn, OPJ_INT32 cas) { + OPJ_INT32 i; if (!cas) { if ((dn > 0) || (sn > 1)) { /* NEW : CASE ONE ELEMENT */ @@ -271,8 +320,8 @@ static void dwt_decode_1(dwt_t *v) { /* <summary> */ /* Forward 9-7 wavelet transform in 1-D. */ /* </summary> */ -static void dwt_encode_1_real(int *a, int dn, int sn, int cas) { - int i; +static void dwt_encode_1_real(OPJ_INT32 *a, OPJ_INT32 dn, OPJ_INT32 sn, OPJ_INT32 cas) { + OPJ_INT32 i; if (!cas) { if ((dn > 0) || (sn > 1)) { /* NEW : CASE ONE ELEMENT */ for (i = 0; i < dn; i++) @@ -306,8 +355,8 @@ static void dwt_encode_1_real(int *a, int dn, int sn, int cas) { } } -static void dwt_encode_stepsize(int stepsize, int numbps, opj_stepsize_t *bandno_stepsize) { - int p, n; +static void dwt_encode_stepsize(OPJ_INT32 stepsize, OPJ_INT32 numbps, opj_stepsize_t *bandno_stepsize) { + OPJ_INT32 p, n; p = int_floorlog2(stepsize) - 13; n = 11 - int_floorlog2(stepsize); bandno_stepsize->mant = (n < 0 ? stepsize >> -n : stepsize << n) & 0x7ff; @@ -323,71 +372,105 @@ static void dwt_encode_stepsize(int stepsize, int numbps, opj_stepsize_t *bandno /* <summary> */ /* Forward 5-3 wavelet transform in 2-D. */ /* </summary> */ -void dwt_encode(opj_tcd_tilecomp_t * tilec) { - int i, j, k; - int *a = NULL; - int *aj = NULL; - int *bj = NULL; - int w, l; +INLINE bool dwt_encode_procedure(opj_tcd_tilecomp_t * tilec,void (*p_function)(OPJ_INT32 *, OPJ_INT32,OPJ_INT32,OPJ_INT32) ) +{ + OPJ_INT32 i, j, k; + OPJ_INT32 *a = 00; + OPJ_INT32 *aj = 00; + OPJ_INT32 *bj = 00; + OPJ_INT32 w, l; + + OPJ_INT32 rw; /* width of the resolution level computed */ + OPJ_INT32 rh; /* height of the resolution level computed */ + OPJ_INT32 l_data_size; + opj_tcd_resolution_t * l_cur_res = 0; + opj_tcd_resolution_t * l_last_res = 0; + w = tilec->x1-tilec->x0; l = tilec->numresolutions-1; a = tilec->data; - for (i = 0; i < l; i++) { - int rw; /* width of the resolution level computed */ - int rh; /* height of the resolution level computed */ - int rw1; /* width of the resolution level once lower than computed one */ - int rh1; /* height of the resolution level once lower than computed one */ - int cas_col; /* 0 = non inversion on horizontal filtering 1 = inversion between low-pass and high-pass filtering */ - int cas_row; /* 0 = non inversion on vertical filtering 1 = inversion between low-pass and high-pass filtering */ - int dn, sn; + l_cur_res = tilec->resolutions + l; + l_last_res = l_cur_res - 1; + + rw = l_cur_res->x1 - l_cur_res->x0; + rh = l_cur_res->y1 - l_cur_res->y0; + + l_data_size = dwt_max_resolution( tilec->resolutions,tilec->numresolutions) * sizeof(OPJ_INT32); + bj = opj_malloc(l_data_size); + if + (! bj) + { + return false; + } + i = l; + + while + (i--) + { + OPJ_INT32 rw1; /* width of the resolution level once lower than computed one */ + OPJ_INT32 rh1; /* height of the resolution level once lower than computed one */ + OPJ_INT32 cas_col; /* 0 = non inversion on horizontal filtering 1 = inversion between low-pass and high-pass filtering */ + OPJ_INT32 cas_row; /* 0 = non inversion on vertical filtering 1 = inversion between low-pass and high-pass filtering */ + OPJ_INT32 dn, sn; - rw = tilec->resolutions[l - i].x1 - tilec->resolutions[l - i].x0; - rh = tilec->resolutions[l - i].y1 - tilec->resolutions[l - i].y0; - rw1= tilec->resolutions[l - i - 1].x1 - tilec->resolutions[l - i - 1].x0; - rh1= tilec->resolutions[l - i - 1].y1 - tilec->resolutions[l - i - 1].y0; + rw = l_cur_res->x1 - l_cur_res->x0; + rh = l_cur_res->y1 - l_cur_res->y0; + rw1 = l_last_res->x1 - l_last_res->x0; + rh1 = l_last_res->y1 - l_last_res->y0; - cas_row = tilec->resolutions[l - i].x0 % 2; - cas_col = tilec->resolutions[l - i].y0 % 2; + cas_row = l_cur_res->x0 & 1; + cas_col = l_cur_res->y0 & 1; sn = rh1; dn = rh - rh1; - bj = (int*)opj_malloc(rh * sizeof(int)); - for (j = 0; j < rw; j++) { + for + (j = 0; j < rw; ++j) + { aj = a + j; - for (k = 0; k < rh; k++) bj[k] = aj[k*w]; - dwt_encode_1(bj, dn, sn, cas_col); + for + (k = 0; k < rh; ++k) + { + bj[k] = aj[k*w]; + } + (*p_function) (bj, dn, sn, cas_col); dwt_deinterleave_v(bj, aj, dn, sn, w, cas_col); } - opj_free(bj); - sn = rw1; dn = rw - rw1; - bj = (int*)opj_malloc(rw * sizeof(int)); - for (j = 0; j < rh; j++) { + for (j = 0; j < rh; j++) + { aj = a + j * w; for (k = 0; k < rw; k++) bj[k] = aj[k]; - dwt_encode_1(bj, dn, sn, cas_row); + (*p_function) (bj, dn, sn, cas_row); dwt_deinterleave_h(bj, aj, dn, sn, cas_row); } - opj_free(bj); + l_cur_res = l_last_res; + --l_last_res; } + opj_free(bj); + return true; +} +/* Forward 5-3 wavelet transform in 2-D. */ +/* </summary> */ +bool dwt_encode(opj_tcd_tilecomp_t * tilec) +{ + return dwt_encode_procedure(tilec,dwt_encode_1); } - /* <summary> */ /* Inverse 5-3 wavelet transform in 2-D. */ /* </summary> */ -void dwt_decode(opj_tcd_tilecomp_t* tilec, int numres) { - dwt_decode_tile(tilec, numres, &dwt_decode_1); +bool dwt_decode(opj_tcd_tilecomp_t* tilec, OPJ_UINT32 numres) { + return dwt_decode_tile(tilec, numres, &dwt_decode_1); } /* <summary> */ /* Get gain of 5-3 wavelet transform. */ /* </summary> */ -int dwt_getgain(int orient) { +OPJ_UINT32 dwt_getgain(OPJ_UINT32 orient) { if (orient == 0) return 0; if (orient == 1 || orient == 2) @@ -398,71 +481,24 @@ int dwt_getgain(int orient) { /* <summary> */ /* Get norm of 5-3 wavelet. */ /* </summary> */ -double dwt_getnorm(int level, int orient) { +OPJ_FLOAT64 dwt_getnorm(OPJ_UINT32 level, OPJ_UINT32 orient) { return dwt_norms[orient][level]; } /* <summary> */ /* Forward 9-7 wavelet transform in 2-D. */ /* </summary> */ - -void dwt_encode_real(opj_tcd_tilecomp_t * tilec) { - int i, j, k; - int *a = NULL; - int *aj = NULL; - int *bj = NULL; - int w, l; - - w = tilec->x1-tilec->x0; - l = tilec->numresolutions-1; - a = tilec->data; - - for (i = 0; i < l; i++) { - int rw; /* width of the resolution level computed */ - int rh; /* height of the resolution level computed */ - int rw1; /* width of the resolution level once lower than computed one */ - int rh1; /* height of the resolution level once lower than computed one */ - int cas_col; /* 0 = non inversion on horizontal filtering 1 = inversion between low-pass and high-pass filtering */ - int cas_row; /* 0 = non inversion on vertical filtering 1 = inversion between low-pass and high-pass filtering */ - int dn, sn; - - rw = tilec->resolutions[l - i].x1 - tilec->resolutions[l - i].x0; - rh = tilec->resolutions[l - i].y1 - tilec->resolutions[l - i].y0; - rw1= tilec->resolutions[l - i - 1].x1 - tilec->resolutions[l - i - 1].x0; - rh1= tilec->resolutions[l - i - 1].y1 - tilec->resolutions[l - i - 1].y0; - - cas_row = tilec->resolutions[l - i].x0 % 2; - cas_col = tilec->resolutions[l - i].y0 % 2; - - sn = rh1; - dn = rh - rh1; - bj = (int*)opj_malloc(rh * sizeof(int)); - for (j = 0; j < rw; j++) { - aj = a + j; - for (k = 0; k < rh; k++) bj[k] = aj[k*w]; - dwt_encode_1_real(bj, dn, sn, cas_col); - dwt_deinterleave_v(bj, aj, dn, sn, w, cas_col); - } - opj_free(bj); - - sn = rw1; - dn = rw - rw1; - bj = (int*)opj_malloc(rw * sizeof(int)); - for (j = 0; j < rh; j++) { - aj = a + j * w; - for (k = 0; k < rw; k++) bj[k] = aj[k]; - dwt_encode_1_real(bj, dn, sn, cas_row); - dwt_deinterleave_h(bj, aj, dn, sn, cas_row); - } - opj_free(bj); - } +bool dwt_encode_real(opj_tcd_tilecomp_t * tilec) +{ + return dwt_encode_procedure(tilec,dwt_encode_1_real); } + /* <summary> */ /* Get gain of 9-7 wavelet transform. */ /* </summary> */ -int dwt_getgain_real(int orient) { +OPJ_UINT32 dwt_getgain_real(OPJ_UINT32 orient) { (void)orient; return 0; } @@ -470,16 +506,16 @@ int dwt_getgain_real(int orient) { /* <summary> */ /* Get norm of 9-7 wavelet. */ /* </summary> */ -double dwt_getnorm_real(int level, int orient) { +OPJ_FLOAT64 dwt_getnorm_real(OPJ_UINT32 level, OPJ_UINT32 orient) { return dwt_norms_real[orient][level]; } -void dwt_calc_explicit_stepsizes(opj_tccp_t * tccp, int prec) { - int numbands, bandno; +void dwt_calc_explicit_stepsizes(opj_tccp_t * tccp, OPJ_UINT32 prec) { + OPJ_UINT32 numbands, bandno; numbands = 3 * tccp->numresolutions - 2; for (bandno = 0; bandno < numbands; bandno++) { - double stepsize; - int resno, level, orient, gain; + OPJ_FLOAT64 stepsize; + OPJ_UINT32 resno, level, orient, gain; resno = (bandno == 0) ? 0 : ((bandno - 1) / 3 + 1); orient = (bandno == 0) ? 0 : ((bandno - 1) % 3 + 1); @@ -488,10 +524,10 @@ void dwt_calc_explicit_stepsizes(opj_tccp_t * tccp, int prec) { if (tccp->qntsty == J2K_CCP_QNTSTY_NOQNT) { stepsize = 1.0; } else { - double norm = dwt_norms_real[orient][level]; + OPJ_FLOAT64 norm = dwt_norms_real[orient][level]; stepsize = (1 << (gain)) / norm; } - dwt_encode_stepsize((int) floor(stepsize * 8192.0), prec + gain, &tccp->stepsizes[bandno]); + dwt_encode_stepsize((OPJ_INT32) floor(stepsize * 8192.0), prec + gain, &tccp->stepsizes[bandno]); } } @@ -499,11 +535,11 @@ void dwt_calc_explicit_stepsizes(opj_tccp_t * tccp, int prec) { /* <summary> */ /* Determine maximum computed resolution level for inverse wavelet transform */ /* </summary> */ -static int dwt_decode_max_resolution(opj_tcd_resolution_t* restrict r, int i) { - int mr = 1; - int w; +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++; + ++r; if( mr < ( w = r->x1 - r->x0 ) ) mr = w ; if( mr < ( w = r->y1 - r->y0 ) ) @@ -516,23 +552,29 @@ static int dwt_decode_max_resolution(opj_tcd_resolution_t* restrict r, int i) { /* <summary> */ /* Inverse wavelet transform in 2-D. */ /* </summary> */ -static void dwt_decode_tile(opj_tcd_tilecomp_t* tilec, int numres, DWT1DFN dwt_1D) { +static 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; - int rw = tr->x1 - tr->x0; /* width of the resolution level computed */ - int rh = tr->y1 - tr->y0; /* height of the resolution level computed */ + 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 */ - int w = tilec->x1 - tilec->x0; + OPJ_UINT32 w = tilec->x1 - tilec->x0; + + h.mem = opj_aligned_malloc(dwt_max_resolution(tr, numres) * sizeof(OPJ_INT32)); + if + (! h.mem) + { + return false; + } - h.mem = opj_aligned_malloc(dwt_decode_max_resolution(tr, numres) * sizeof(int)); v.mem = h.mem; while( --numres) { - int * restrict tiledp = tilec->data; - int j; + OPJ_INT32 * restrict tiledp = tilec->data; + OPJ_UINT32 j; ++tr; h.sn = rw; @@ -547,14 +589,14 @@ static void dwt_decode_tile(opj_tcd_tilecomp_t* tilec, int numres, DWT1DFN dwt_1 for(j = 0; j < rh; ++j) { dwt_interleave_h(&h, &tiledp[j*w]); (dwt_1D)(&h); - memcpy(&tiledp[j*w], h.mem, rw * sizeof(int)); + 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){ - int k; + OPJ_UINT32 k; dwt_interleave_v(&v, &tiledp[j], w); (dwt_1D)(&v); for(k = 0; k < rh; ++k) { @@ -563,61 +605,62 @@ static void dwt_decode_tile(opj_tcd_tilecomp_t* tilec, int numres, DWT1DFN dwt_1 } } opj_aligned_free(h.mem); + return 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); - int count = w->sn; - int i, k; +static void v4dwt_interleave_h(v4dwt_t* restrict w, OPJ_FLOAT32* restrict a, OPJ_INT32 x, OPJ_INT32 size){ + OPJ_FLOAT32* restrict bi = (OPJ_FLOAT32*) (w->wavelet + w->cas); + OPJ_INT32 count = w->sn; + OPJ_INT32 i, k; for(k = 0; k < 2; ++k){ for(i = 0; i < count; ++i){ - int j = i; + OPJ_INT32 j = i; bi[i*8 ] = a[j]; j += x; - if(j > size) continue; + if(j >= size) continue; bi[i*8 + 1] = a[j]; j += x; - if(j > size) continue; + if(j >= size) continue; bi[i*8 + 2] = a[j]; j += x; - if(j > size) continue; + if(j >= size) continue; bi[i*8 + 3] = a[j]; } - bi = (float*) (w->wavelet + 1 - w->cas); + bi = (OPJ_FLOAT32*) (w->wavelet + 1 - w->cas); a += w->sn; size -= w->sn; count = w->dn; } } -static void v4dwt_interleave_v(v4dwt_t* restrict v , float* restrict a , int x){ +static void v4dwt_interleave_v(v4dwt_t* restrict v , OPJ_FLOAT32* restrict a , OPJ_INT32 x){ v4* restrict bi = v->wavelet + v->cas; - int i; + OPJ_INT32 i; for(i = 0; i < v->sn; ++i){ - memcpy(&bi[i*2], &a[i*x], 4 * sizeof(float)); + memcpy(&bi[i*2], &a[i*x], 4 * sizeof(OPJ_FLOAT32)); } a += v->sn * x; bi = v->wavelet + 1 - v->cas; for(i = 0; i < v->dn; ++i){ - memcpy(&bi[i*2], &a[i*x], 4 * sizeof(float)); + memcpy(&bi[i*2], &a[i*x], 4 * sizeof(OPJ_FLOAT32)); } } #ifdef __SSE__ -static void v4dwt_decode_step1_sse(v4* w, int count, const __m128 c){ +static void v4dwt_decode_step1_sse(v4* w, OPJ_INT32 count, const __m128 c){ __m128* restrict vw = (__m128*) w; - int i; + OPJ_INT32 i; for(i = 0; i < count; ++i){ __m128 tmp = vw[i*2]; vw[i*2] = tmp * c; } } -static void v4dwt_decode_step2_sse(v4* l, v4* w, int k, int m, __m128 c){ +static void v4dwt_decode_step2_sse(v4* l, v4* w, OPJ_INT32 k, OPJ_INT32 m, __m128 c){ __m128* restrict vl = (__m128*) l; __m128* restrict vw = (__m128*) w; - int i; + OPJ_INT32 i; for(i = 0; i < m; ++i){ __m128 tmp1 = vl[ 0]; __m128 tmp2 = vw[-1]; @@ -640,14 +683,14 @@ static void v4dwt_decode_step2_sse(v4* l, v4* w, int k, int m, __m128 c){ #else -static void v4dwt_decode_step1(v4* w, int count, const float c){ - float* restrict fw = (float*) w; - int i; +static void v4dwt_decode_step1(v4* w, OPJ_INT32 count, const OPJ_FLOAT32 c){ + OPJ_FLOAT32* restrict fw = (OPJ_FLOAT32*) w; + OPJ_INT32 i; for(i = 0; i < count; ++i){ - float tmp1 = fw[i*8 ]; - float tmp2 = fw[i*8 + 1]; - float tmp3 = fw[i*8 + 2]; - float tmp4 = fw[i*8 + 3]; + OPJ_FLOAT32 tmp1 = fw[i*8 ]; + OPJ_FLOAT32 tmp2 = fw[i*8 + 1]; + OPJ_FLOAT32 tmp3 = fw[i*8 + 2]; + OPJ_FLOAT32 tmp4 = fw[i*8 + 3]; fw[i*8 ] = tmp1 * c; fw[i*8 + 1] = tmp2 * c; fw[i*8 + 2] = tmp3 * c; @@ -655,23 +698,23 @@ static void v4dwt_decode_step1(v4* w, int count, const float c){ } } -static void v4dwt_decode_step2(v4* l, v4* w, int k, int m, float c){ - float* restrict fl = (float*) l; - float* restrict fw = (float*) w; - int i; +static void v4dwt_decode_step2(v4* l, v4* w, OPJ_INT32 k, OPJ_INT32 m, OPJ_FLOAT32 c){ + OPJ_FLOAT32* restrict fl = (OPJ_FLOAT32*) l; + OPJ_FLOAT32* restrict fw = (OPJ_FLOAT32*) w; + OPJ_INT32 i; for(i = 0; i < m; ++i){ - float tmp1_1 = fl[0]; - float tmp1_2 = fl[1]; - float tmp1_3 = fl[2]; - float tmp1_4 = fl[3]; - float tmp2_1 = fw[-4]; - float tmp2_2 = fw[-3]; - float tmp2_3 = fw[-2]; - float tmp2_4 = fw[-1]; - float tmp3_1 = fw[0]; - float tmp3_2 = fw[1]; - float tmp3_3 = fw[2]; - float tmp3_4 = fw[3]; + OPJ_FLOAT32 tmp1_1 = fl[0]; + OPJ_FLOAT32 tmp1_2 = fl[1]; + OPJ_FLOAT32 tmp1_3 = fl[2]; + OPJ_FLOAT32 tmp1_4 = fl[3]; + OPJ_FLOAT32 tmp2_1 = fw[-4]; + OPJ_FLOAT32 tmp2_2 = fw[-3]; + OPJ_FLOAT32 tmp2_3 = fw[-2]; + OPJ_FLOAT32 tmp2_4 = fw[-1]; + OPJ_FLOAT32 tmp3_1 = fw[0]; + OPJ_FLOAT32 tmp3_2 = fw[1]; + OPJ_FLOAT32 tmp3_3 = fw[2]; + OPJ_FLOAT32 tmp3_4 = fw[3]; fw[-4] = tmp2_1 + ((tmp1_1 + tmp3_1) * c); fw[-3] = tmp2_2 + ((tmp1_2 + tmp3_2) * c); fw[-2] = tmp2_3 + ((tmp1_3 + tmp3_3) * c); @@ -680,20 +723,20 @@ static void v4dwt_decode_step2(v4* l, v4* w, int k, int m, float c){ fw += 8; } if(m < k){ - float c1; - float c2; - float c3; - float c4; + OPJ_FLOAT32 c1; + OPJ_FLOAT32 c2; + OPJ_FLOAT32 c3; + OPJ_FLOAT32 c4; c += c; c1 = fl[0] * c; c2 = fl[1] * c; c3 = fl[2] * c; c4 = fl[3] * c; for(; m < k; ++m){ - float tmp1 = fw[-4]; - float tmp2 = fw[-3]; - float tmp3 = fw[-2]; - float tmp4 = fw[-1]; + OPJ_FLOAT32 tmp1 = fw[-4]; + OPJ_FLOAT32 tmp2 = fw[-3]; + OPJ_FLOAT32 tmp3 = fw[-2]; + OPJ_FLOAT32 tmp4 = fw[-1]; fw[-4] = tmp1 + c1; fw[-3] = tmp2 + c2; fw[-2] = tmp3 + c3; @@ -709,7 +752,7 @@ static void v4dwt_decode_step2(v4* l, v4* w, int k, int m, float c){ /* Inverse 9-7 wavelet transform in 1-D. */ /* </summary> */ static void v4dwt_decode(v4dwt_t* restrict dwt){ - int a, b; + OPJ_INT32 a, b; if(dwt->cas == 0) { if(!((dwt->dn > 0) || (dwt->sn > 1))){ return; @@ -726,14 +769,14 @@ static void v4dwt_decode(v4dwt_t* restrict dwt){ #ifdef __SSE__ v4dwt_decode_step1_sse(dwt->wavelet+a, dwt->sn, _mm_set1_ps(K)); v4dwt_decode_step1_sse(dwt->wavelet+b, dwt->dn, _mm_set1_ps(c13318)); - v4dwt_decode_step2_sse(dwt->wavelet+b, dwt->wavelet+a+1, dwt->sn, int_min(dwt->sn, dwt->dn-a), _mm_set1_ps(dwt_delta)); + v4dwt_decode_step2_sse(dwt->wavelet+b, dwt->wavelet+a+1, dwt->sn, int_min(dwt->sn, dwt->dn-a), _mm_set1_ps(delta)); v4dwt_decode_step2_sse(dwt->wavelet+a, dwt->wavelet+b+1, dwt->dn, int_min(dwt->dn, dwt->sn-b), _mm_set1_ps(dwt_gamma)); v4dwt_decode_step2_sse(dwt->wavelet+b, dwt->wavelet+a+1, dwt->sn, int_min(dwt->sn, dwt->dn-a), _mm_set1_ps(dwt_beta)); v4dwt_decode_step2_sse(dwt->wavelet+a, dwt->wavelet+b+1, dwt->dn, int_min(dwt->dn, dwt->sn-b), _mm_set1_ps(dwt_alpha)); #else v4dwt_decode_step1(dwt->wavelet+a, dwt->sn, K); v4dwt_decode_step1(dwt->wavelet+b, dwt->dn, c13318); - v4dwt_decode_step2(dwt->wavelet+b, dwt->wavelet+a+1, dwt->sn, int_min(dwt->sn, dwt->dn-a), dwt_delta); + v4dwt_decode_step2(dwt->wavelet+b, dwt->wavelet+a+1, dwt->sn, int_min(dwt->sn, dwt->dn-a), delta); v4dwt_decode_step2(dwt->wavelet+a, dwt->wavelet+b+1, dwt->dn, int_min(dwt->dn, dwt->sn-b), dwt_gamma); v4dwt_decode_step2(dwt->wavelet+b, dwt->wavelet+a+1, dwt->sn, int_min(dwt->sn, dwt->dn-a), dwt_beta); v4dwt_decode_step2(dwt->wavelet+a, dwt->wavelet+b+1, dwt->dn, int_min(dwt->dn, dwt->sn-b), dwt_alpha); @@ -743,24 +786,24 @@ static void v4dwt_decode(v4dwt_t* restrict dwt){ /* <summary> */ /* Inverse 9-7 wavelet transform in 2-D. */ /* </summary> */ -void dwt_decode_real(opj_tcd_tilecomp_t* restrict tilec, int numres){ +bool dwt_decode_real(opj_tcd_tilecomp_t* restrict tilec, OPJ_UINT32 numres){ v4dwt_t h; v4dwt_t v; opj_tcd_resolution_t* res = tilec->resolutions; - int rw = res->x1 - res->x0; /* width of the resolution level computed */ - int rh = res->y1 - res->y0; /* height of the resolution level computed */ + OPJ_UINT32 rw = res->x1 - res->x0; /* width of the resolution level computed */ + OPJ_UINT32 rh = res->y1 - res->y0; /* height of the resolution level computed */ - int w = tilec->x1 - tilec->x0; + OPJ_UINT32 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) { - float * restrict aj = (float*) tilec->data; - int bufsize = (tilec->x1 - tilec->x0) * (tilec->y1 - tilec->y0); - int j; + OPJ_FLOAT32 * restrict aj = (OPJ_FLOAT32*) tilec->data; + OPJ_UINT32 bufsize = (tilec->x1 - tilec->x0) * (tilec->y1 - tilec->y0); + OPJ_INT32 j; h.sn = rw; v.sn = rh; @@ -771,22 +814,26 @@ void dwt_decode_real(opj_tcd_tilecomp_t* restrict tilec, int numres){ rh = res->y1 - res->y0; /* height of the resolution level computed */ h.dn = rw - h.sn; - h.cas = res->x0 % 2; + h.cas = res->x0 & 1; for(j = rh; j > 0; j -= 4){ v4dwt_interleave_h(&h, aj, w, bufsize); v4dwt_decode(&h); if(j >= 4){ - int k; - for(k = rw; --k >= 0;){ + OPJ_INT32 k = rw; + while + (--k >= 0) + { aj[k ] = h.wavelet[k].f[0]; aj[k+w ] = h.wavelet[k].f[1]; aj[k+w*2] = h.wavelet[k].f[2]; aj[k+w*3] = h.wavelet[k].f[3]; } }else{ - int k; - for(k = rw; --k >= 0;){ + OPJ_INT32 k = rw; + while + (--k >= 0) + { switch(j) { case 3: aj[k+w*2] = h.wavelet[k].f[2]; case 2: aj[k+w ] = h.wavelet[k].f[1]; @@ -801,19 +848,19 @@ void dwt_decode_real(opj_tcd_tilecomp_t* restrict tilec, int numres){ v.dn = rh - v.sn; v.cas = res->y0 % 2; - aj = (float*) tilec->data; + aj = (OPJ_FLOAT32*) tilec->data; for(j = rw; j > 0; j -= 4){ v4dwt_interleave_v(&v, aj, w); v4dwt_decode(&v); if(j >= 4){ - int k; + OPJ_UINT32 k; for(k = 0; k < rh; ++k){ - memcpy(&aj[k*w], &v.wavelet[k], 4 * sizeof(float)); + memcpy(&aj[k*w], &v.wavelet[k], 4 * sizeof(OPJ_FLOAT32)); } }else{ - int k; + OPJ_UINT32 k; for(k = 0; k < rh; ++k){ - memcpy(&aj[k*w], &v.wavelet[k], j * sizeof(float)); + memcpy(&aj[k*w], &v.wavelet[k], j * sizeof(OPJ_FLOAT32)); } } aj += 4; @@ -821,5 +868,6 @@ void dwt_decode_real(opj_tcd_tilecomp_t* restrict tilec, int numres){ } opj_aligned_free(h.wavelet); + return true; } diff --git a/libopenjpeg/dwt.h b/libopenjpeg/dwt.h index adf73e54..d200b065 100644 --- a/libopenjpeg/dwt.h +++ b/libopenjpeg/dwt.h @@ -5,6 +5,7 @@ * Copyright (c) 2002-2003, Yannick Verschueren * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -39,6 +40,10 @@ The functions in DWT.C have for goal to realize forward and inverse discret wave transform with filter 5-3 (reversible) and filter 9-7 (irreversible). The functions in DWT.C are used by some function in TCD.C. */ +#include "openjpeg.h" + +struct opj_tcd_tilecomp; +struct opj_tccp; /** @defgroup DWT DWT - Implementation of a discrete wavelet transform */ /*@{*/ @@ -52,59 +57,59 @@ Forward 5-3 wavelet tranform in 2-D. Apply a reversible DWT transform to a component of an image. @param tilec Tile component information (current tile) */ -void dwt_encode(opj_tcd_tilecomp_t * tilec); +bool dwt_encode(struct opj_tcd_tilecomp * tilec); /** Inverse 5-3 wavelet tranform in 2-D. 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 */ -void dwt_decode(opj_tcd_tilecomp_t* tilec, int numres); +bool dwt_decode(struct opj_tcd_tilecomp* 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) @return Returns 0 if orient = 0, returns 1 if orient = 1 or 2, returns 2 otherwise */ -int dwt_getgain(int orient); +OPJ_UINT32 dwt_getgain(OPJ_UINT32 orient); /** Get the norm of a wavelet function of a subband at a specified level for the reversible 5-3 DWT. @param level Level of the wavelet function @param orient Band of the wavelet function @return Returns the norm of the wavelet function */ -double dwt_getnorm(int level, int orient); +OPJ_FLOAT64 dwt_getnorm(OPJ_UINT32 level, OPJ_UINT32 orient); /** Forward 9-7 wavelet transform in 2-D. Apply an irreversible DWT transform to a component of an image. @param tilec Tile component information (current tile) */ -void dwt_encode_real(opj_tcd_tilecomp_t * tilec); +bool dwt_encode_real(struct opj_tcd_tilecomp * tilec); /** 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); +bool dwt_decode_real(struct opj_tcd_tilecomp* tilec, OPJ_UINT32 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) @return Returns the gain of the 9-7 wavelet transform */ -int dwt_getgain_real(int orient); +OPJ_UINT32 dwt_getgain_real(OPJ_UINT32 orient); /** Get the norm of a wavelet function of a subband at a specified level for the irreversible 9-7 DWT @param level Level of the wavelet function @param orient Band of the wavelet function @return Returns the norm of the 9-7 wavelet */ -double dwt_getnorm_real(int level, int orient); +OPJ_FLOAT64 dwt_getnorm_real(OPJ_UINT32 level, OPJ_UINT32 orient); /** Explicit calculation of the Quantization Stepsizes @param tccp Tile-component coding parameters @param prec Precint analyzed */ -void dwt_calc_explicit_stepsizes(opj_tccp_t * tccp, int prec); +void dwt_calc_explicit_stepsizes(struct opj_tccp * tccp, OPJ_UINT32 prec); /* ----------------------------------------------------------------------- */ /*@}*/ diff --git a/libopenjpeg/event.c b/libopenjpeg/event.c index 291ff585..eb40c6aa 100644 --- a/libopenjpeg/event.c +++ b/libopenjpeg/event.c @@ -24,84 +24,59 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include "event.h" +#include "openjpeg.h" #include "opj_includes.h" + /* ========================================================== Utility functions ==========================================================*/ #if !defined(_MSC_VER) && !defined(__MINGW32__) -static char* -i2a(unsigned i, char *a, unsigned r) { +static OPJ_CHAR* +i2a(OPJ_UINT32 i, OPJ_CHAR *a, OPJ_UINT32 r) { if (i/r > 0) a = i2a(i/r,a,r); *a = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[i%r]; return a+1; } - -/** - Transforms integer i into an ascii string and stores the result in a; - string is encoded in the base indicated by r. - @param i Number to be converted - @param a String result - @param r Base of value; must be in the range 2 - 36 - @return Returns a -*/ -static char * -_itoa(int i, char *a, int r) { - r = ((r < 2) || (r > 36)) ? 10 : r; - if(i < 0) { - *a = '-'; - *i2a(-i, a+1, r) = 0; - } - else *i2a(i, a, r) = 0; - return a; -} - -#endif /* !WIN32 */ - +#endif /* ----------------------------------------------------------------------- */ -opj_event_mgr_t* OPJ_CALLCONV opj_set_event_mgr(opj_common_ptr cinfo, opj_event_mgr_t *event_mgr, void *context) { - if(cinfo) { - opj_event_mgr_t *previous = cinfo->event_mgr; - cinfo->event_mgr = event_mgr; - cinfo->client_data = context; - return previous; - } - - return NULL; -} - -bool opj_event_msg(opj_common_ptr cinfo, int event_type, const char *fmt, ...) { +bool opj_event_msg(opj_event_mgr_t * p_event_mgr, OPJ_INT32 event_type, const OPJ_CHAR *fmt, ...) { #define MSG_SIZE 512 /* 512 bytes should be more than enough for a short message */ - opj_msg_callback msg_handler = NULL; + opj_msg_callback msg_handler = 00; + void * l_data = 00; - opj_event_mgr_t *event_mgr = cinfo->event_mgr; - if(event_mgr != NULL) { + + if(p_event_mgr != 00) { switch(event_type) { case EVT_ERROR: - msg_handler = event_mgr->error_handler; + msg_handler = p_event_mgr->error_handler; + l_data = p_event_mgr->m_error_data; break; case EVT_WARNING: - msg_handler = event_mgr->warning_handler; + msg_handler = p_event_mgr->warning_handler; + l_data = p_event_mgr->m_warning_data; break; case EVT_INFO: - msg_handler = event_mgr->info_handler; + msg_handler = p_event_mgr->info_handler; + l_data = p_event_mgr->m_info_data; break; default: break; } - if(msg_handler == NULL) { + if(msg_handler == 00) { return false; } } else { return false; } - if ((fmt != NULL) && (event_mgr != NULL)) { + if ((fmt != 00) && (p_event_mgr != 00)) { va_list arg; - int str_length/*, i, j*/; /* UniPG */ - char message[MSG_SIZE]; + OPJ_INT32 str_length/*, i, j*/; /* UniPG */ + OPJ_CHAR message[MSG_SIZE]; memset(message, 0, MSG_SIZE); /* initialize the optional parameter list */ va_start(arg, fmt); @@ -113,7 +88,7 @@ bool opj_event_msg(opj_common_ptr cinfo, int event_type, const char *fmt, ...) { va_end(arg); /* output the message to the user program */ - msg_handler(message, cinfo->client_data); + msg_handler(message, l_data); } return true; diff --git a/libopenjpeg/event.h b/libopenjpeg/event.h index 11910b0e..4c035a88 100644 --- a/libopenjpeg/event.h +++ b/libopenjpeg/event.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,12 +26,39 @@ */ #ifndef __EVENT_H #define __EVENT_H + +#include "openjpeg.h" + /** @file event.h @brief Implementation of a event callback system The functions in EVENT.C have for goal to send output messages (errors, warnings, debug) to the user. */ +/** +Message handler object +used for +<ul> +<li>Error messages +<li>Warning messages +<li>Debugging messages +</ul> +*/ +typedef struct opj_event_mgr +{ + /** Data to call the event manager upon */ + void * m_error_data; + /** Data to call the event manager upon */ + void * m_warning_data; + /** Data to call the event manager upon */ + void * m_info_data; + /** Error message callback if available, NULL otherwise */ + opj_msg_callback error_handler; + /** Warning message callback if available, NULL otherwise */ + opj_msg_callback warning_handler; + /** Debug message callback if available, NULL otherwise */ + opj_msg_callback info_handler; +} opj_event_mgr_t; #define EVT_ERROR 1 /**< Error event type */ #define EVT_WARNING 2 /**< Warning event type */ @@ -43,13 +71,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) -@return Returns true if successful, returns false otherwise + * Writes formatted data to a string and send the string to a user callback. + * @param p_event_mgr the event manager to display messages. + * @param event_type Event type of the message + * @param fmt Format-control string (plus optionnal arguments) + * @return Returns true if successful, returns false otherwise */ -bool opj_event_msg(opj_common_ptr cinfo, int event_type, const char *fmt, ...); +bool opj_event_msg(struct opj_event_mgr * p_event_mgr, OPJ_INT32 event_type, const OPJ_CHAR *fmt, ...); /* ----------------------------------------------------------------------- */ /*@}*/ diff --git a/libopenjpeg/fix.h b/libopenjpeg/fix.h index bcb2acb5..f4bb87f6 100644 --- a/libopenjpeg/fix.h +++ b/libopenjpeg/fix.h @@ -31,11 +31,8 @@ #ifndef __FIX_H #define __FIX_H -#if defined(_MSC_VER) || defined(__BORLANDC__) -#define int64 __int64 -#else -#define int64 long long -#endif +#include "openjpeg.h" +#include "opj_includes.h" /** @file fix.h @@ -43,7 +40,6 @@ The functions in FIX.H have for goal to realize specific multiplication. */ - /** @defgroup FIX FIX - Implementation of operations of specific multiplication */ /*@{*/ @@ -54,7 +50,7 @@ Multiply two fixed-precision rational numbers. @return Returns a * b */ static INLINE int fix_mul(int a, int b) { - int64 temp = (int64) a * (int64) b ; + OPJ_INT64 temp = (OPJ_INT64) a * (OPJ_INT64) b ; temp += temp & 4096; return (int) (temp >> 13) ; } diff --git a/libopenjpeg/function_list.c b/libopenjpeg/function_list.c new file mode 100644 index 00000000..29eab611 --- /dev/null +++ b/libopenjpeg/function_list.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "function_list.h" +#include "opj_includes.h" +#include "opj_malloc.h" +/** + * Default size of the validation list, if not sufficient, data will be reallocated with a double size. + */ +#define OPJ_VALIDATION_SIZE 10 + +/** + * Creates a validation list. + * + * @return the newly created validation list. + */ +opj_procedure_list_t * opj_procedure_list_create() +{ + /* memory allocation */ + opj_procedure_list_t * l_validation = (opj_procedure_list_t *) opj_malloc(sizeof(opj_procedure_list_t)); + if + (! l_validation) + { + return 00; + } + /* initialization */ + memset(l_validation,0,sizeof(opj_procedure_list_t)); + l_validation->m_nb_max_procedures = OPJ_VALIDATION_SIZE; + l_validation->m_procedures = opj_malloc(OPJ_VALIDATION_SIZE * sizeof(opj_procedure)); + if + (! l_validation->m_procedures) + { + opj_free(l_validation); + return 00; + } + memset(l_validation->m_procedures,0,OPJ_VALIDATION_SIZE * sizeof(opj_procedure)); + return l_validation; +} + + + +/** + * Destroys a validation list. + * + * @param p_list the list to destroy. + */ +void opj_procedure_list_destroy(opj_procedure_list_t * p_list) +{ + if + (! p_list) + { + return; + } + /* initialization */ + if + (p_list->m_procedures) + { + opj_free(p_list->m_procedures); + } + opj_free(p_list); +} + +/** + * Adds a new validation procedure. + * + * @param p_validation_list the list of procedure to modify. + * @param p_procedure the procedure to add. + */ +bool opj_procedure_list_add_procedure (opj_procedure_list_t * p_validation_list, opj_procedure p_procedure) +{ + if + (p_validation_list->m_nb_max_procedures == p_validation_list->m_nb_procedures) + { + p_validation_list->m_nb_max_procedures += OPJ_VALIDATION_SIZE; + p_validation_list->m_procedures = opj_realloc(p_validation_list->m_procedures,p_validation_list->m_nb_max_procedures * sizeof(opj_procedure)); + if + (! p_validation_list->m_procedures) + { + p_validation_list->m_nb_max_procedures = 0; + p_validation_list->m_nb_procedures = 0; + return false; + } + } + p_validation_list->m_procedures[p_validation_list->m_nb_procedures] = p_procedure; + ++p_validation_list->m_nb_procedures; + return true; +} + +/** + * Gets the number of validation procedures. + * + * @param p_validation_list the list of procedure to modify. + * + * @return the number of validation procedures. + */ +OPJ_UINT32 opj_procedure_list_get_nb_procedures (opj_procedure_list_t * p_validation_list) +{ + return p_validation_list->m_nb_procedures; +} + +/** + * Gets the pointer on the first validation procedure. This function is similar to the C++ + * iterator class to iterate through all the procedures inside the validation list. + * the caller does not take ownership of the pointer. + * + * @param p_validation_list the list of procedure to get the first procedure from. + * + * @return a pointer to the first procedure. + */ +opj_procedure* opj_procedure_list_get_first_procedure (opj_procedure_list_t * p_validation_list) +{ + return p_validation_list->m_procedures; +} + +/** + * Clears the list of validation procedures. + * + * @param p_validation_list the list of procedure to clear. + * + */ +void opj_procedure_list_clear (opj_procedure_list_t * p_validation_list) +{ + p_validation_list->m_nb_procedures = 0; +} diff --git a/libopenjpeg/function_list.h b/libopenjpeg/function_list.h new file mode 100644 index 00000000..7cfedf10 --- /dev/null +++ b/libopenjpeg/function_list.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __FUNCTION_LIST_H +#define __FUNCTION_LIST_H + +/** + * @file function_list.h + * @brief Implementation of a list of procedures. + + * The functions in validation.c aims to have access to a list of procedures. +*/ + +/** @defgroup validation validation procedure*/ +/*@{*/ + +#include "openjpeg.h" +/************************************************************************************************** + ***************************************** FORWARD DECLARATION ************************************ + **************************************************************************************************/ +struct opj_jp2; + +/** + * ARGGGG, when will the template be added to the C language ??? + * in order not to have to duplicate the code in a vast number of times, use void * and downcast + * it after => UGLY but faster and easier + * TODO : make the class template in C++, use STL vector or duplicate code for each procedure type. + */ +typedef void * opj_procedure; + +/** + * A list of procedures. +*/ +typedef struct opj_procedure_list +{ + /** + * The number of validation procedures. + */ + OPJ_UINT32 m_nb_procedures; + /** + * The number of the array of validation procedures. + */ + OPJ_UINT32 m_nb_max_procedures; + /** + * The array of procedures. + */ + opj_procedure * m_procedures; + +} opj_procedure_list_t; + +/* ----------------------------------------------------------------------- */ + +/** + * Creates a validation list. + * + * @return the newly created validation list. + */ +opj_procedure_list_t * opj_procedure_list_create(); + +/** + * Destroys a validation list. + * + * @param p_list the list to destroy. + */ +void opj_procedure_list_destroy(opj_procedure_list_t * p_list); + +/** + * Adds a new validation procedure. + * + * @param p_validation_list the list of procedure to modify. + * @param p_procedure the procedure to add. + * + * @return true if the procedure could ne added. + */ +bool opj_procedure_list_add_procedure (opj_procedure_list_t * p_validation_list, opj_procedure p_procedure); + +/** + * Gets the number of validation procedures. + * + * @param p_validation_list the list of procedure to modify. + * + * @return the number of validation procedures. + */ +OPJ_UINT32 opj_procedure_list_get_nb_procedures (opj_procedure_list_t * p_validation_list); + +/** + * Gets the pointer on the first validation procedure. This function is similar to the C++ + * iterator class to iterate through all the procedures inside the validation list. + * the caller does not take ownership of the pointer. + * + * @param p_validation_list the list of procedure to get the first procedure from. + * + * @return a pointer to the first procedure. + */ +opj_procedure* opj_procedure_list_get_first_procedure (opj_procedure_list_t * p_validation_list); + + +/** + * Clears the list of validation procedures. + * + * @param p_validation_list the list of procedure to clear. + * + */ +void opj_procedure_list_clear (opj_procedure_list_t * p_validation_list); + + +#endif /* __FUNCTION_LIST_H */ + diff --git a/libopenjpeg/image.c b/libopenjpeg/image.c index 30b7d139..c6faffd9 100644 --- a/libopenjpeg/image.c +++ b/libopenjpeg/image.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -23,29 +24,38 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ - -#include "opj_includes.h" +#include "image.h" +#include "openjpeg.h" +#include "opj_malloc.h" +#include "j2k.h" +#include "int.h" opj_image_t* opj_image_create0(void) { - opj_image_t *image = (opj_image_t*)opj_calloc(1, sizeof(opj_image_t)); + opj_image_t *image = (opj_image_t*)opj_malloc(sizeof(opj_image_t)); + memset(image,0,sizeof(opj_image_t)); return image; } -opj_image_t* OPJ_CALLCONV opj_image_create(int numcmpts, opj_image_cmptparm_t *cmptparms, OPJ_COLOR_SPACE clrspc) { - int compno; - opj_image_t *image = NULL; +opj_image_t* OPJ_CALLCONV opj_image_create(OPJ_UINT32 numcmpts, opj_image_cmptparm_t *cmptparms, OPJ_COLOR_SPACE clrspc) { + OPJ_UINT32 compno; + opj_image_t *image = 00; - image = (opj_image_t*) opj_calloc(1, sizeof(opj_image_t)); - if(image) { + image = (opj_image_t*) opj_malloc(sizeof(opj_image_t)); + if + (image) + { + memset(image,0,sizeof(opj_image_t)); image->color_space = clrspc; image->numcomps = numcmpts; /* allocate memory for the per-component information */ image->comps = (opj_image_comp_t*)opj_malloc(image->numcomps * sizeof(opj_image_comp_t)); - if(!image->comps) { - fprintf(stderr,"Unable to allocate memory for image.\n"); + if + (!image->comps) + { opj_image_destroy(image); - return NULL; + return 00; } + memset(image->comps,0,image->numcomps * sizeof(opj_image_comp_t)); /* create the individual image components */ for(compno = 0; compno < numcmpts; compno++) { opj_image_comp_t *comp = &image->comps[compno]; @@ -56,24 +66,64 @@ opj_image_t* OPJ_CALLCONV opj_image_create(int numcmpts, opj_image_cmptparm_t *c comp->x0 = cmptparms[compno].x0; comp->y0 = cmptparms[compno].y0; comp->prec = cmptparms[compno].prec; - comp->bpp = cmptparms[compno].bpp; comp->sgnd = cmptparms[compno].sgnd; - comp->data = (int*) opj_calloc(comp->w * comp->h, sizeof(int)); - if(!comp->data) { - fprintf(stderr,"Unable to allocate memory for image.\n"); + comp->data = (OPJ_INT32*) opj_calloc(comp->w * comp->h, sizeof(OPJ_INT32)); + if + (!comp->data) + { opj_image_destroy(image); - return NULL; + return 00; } } } + return image; +} + +opj_image_t* OPJ_CALLCONV opj_image_tile_create(OPJ_UINT32 numcmpts, opj_image_cmptparm_t *cmptparms, OPJ_COLOR_SPACE clrspc) { + OPJ_UINT32 compno; + opj_image_t *image = 00; + image = (opj_image_t*) opj_malloc(sizeof(opj_image_t)); + if + (image) + { + memset(image,0,sizeof(opj_image_t)); + image->color_space = clrspc; + image->numcomps = numcmpts; + /* allocate memory for the per-component information */ + image->comps = (opj_image_comp_t*)opj_malloc(image->numcomps * sizeof(opj_image_comp_t)); + if + (!image->comps) + { + opj_image_destroy(image); + return 00; + } + memset(image->comps,0,image->numcomps * sizeof(opj_image_comp_t)); + /* create the individual image components */ + for(compno = 0; compno < numcmpts; compno++) { + opj_image_comp_t *comp = &image->comps[compno]; + comp->dx = cmptparms[compno].dx; + comp->dy = cmptparms[compno].dy; + comp->w = cmptparms[compno].w; + comp->h = cmptparms[compno].h; + comp->x0 = cmptparms[compno].x0; + comp->y0 = cmptparms[compno].y0; + comp->prec = cmptparms[compno].prec; + comp->sgnd = cmptparms[compno].sgnd; + comp->data = 0; + } + } return image; } void OPJ_CALLCONV opj_image_destroy(opj_image_t *image) { - int i; - if(image) { - if(image->comps) { + OPJ_UINT32 i; + if + (image) + { + if + (image->comps) + { /* image components */ for(i = 0; i < image->numcomps; i++) { opj_image_comp_t *image_comp = &image->comps[i]; @@ -87,3 +137,39 @@ 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_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 04c362eb..91582543 100644 --- a/libopenjpeg/image.h +++ b/libopenjpeg/image.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,7 +32,8 @@ The functions in IMAGE.C have for goal to realize operations on images. */ - +struct opj_image; +struct opj_cp; /** @defgroup IMAGE IMAGE - Implementation of operations on images */ /*@{*/ @@ -40,7 +42,15 @@ Create an empty image @todo this function should be removed @return returns an empty image if successful, returns NULL otherwise */ -opj_image_t* opj_image_create0(void); +struct opj_image* 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 * p_cp); /*@}*/ diff --git a/libopenjpeg/int.h b/libopenjpeg/int.h index 4e5fe08e..0bc58fa9 100644 --- a/libopenjpeg/int.h +++ b/libopenjpeg/int.h @@ -5,6 +5,7 @@ * Copyright (c) 2002-2003, Yannick Verschueren * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -36,7 +37,8 @@ The functions in INT.H have for goal to realize operations on integers. */ - +#include "openjpeg.h" +#include "opj_includes.h" /** @defgroup INT INT - Implementation of operations on integers */ /*@{*/ @@ -47,14 +49,31 @@ The functions in INT.H have for goal to realize operations on integers. Get the minimum of two integers @return Returns a if a < b else b */ -static INLINE int int_min(int a, int b) { +static INLINE OPJ_INT32 int_min(OPJ_INT32 a, OPJ_INT32 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 +*/ +static INLINE OPJ_INT32 int_max(OPJ_INT32 a, OPJ_INT32 b) { + return (a > b) ? a : b; +} + /** Get the maximum of two integers @return Returns a if a > b else b */ -static INLINE int int_max(int a, int b) { +static INLINE OPJ_UINT32 uint_max(OPJ_UINT32 a, OPJ_UINT32 b) { return (a > b) ? a : b; } /** @@ -66,7 +85,7 @@ Clamp an integer inside an interval <li>Returns min if (a < min) </ul> */ -static INLINE int int_clamp(int a, int min, int max) { +static INLINE OPJ_INT32 int_clamp(OPJ_INT32 a, OPJ_INT32 min, OPJ_INT32 max) { if (a < min) return min; if (a > max) @@ -76,41 +95,62 @@ static INLINE int int_clamp(int a, int min, int max) { /** @return Get absolute value of integer */ -static INLINE int int_abs(int a) { +static INLINE OPJ_INT32 int_abs(OPJ_INT32 a) { return a < 0 ? -a : a; } /** Divide an integer and round upwards @return Returns a divided by b */ -static INLINE int int_ceildiv(int a, int b) { +static INLINE OPJ_INT32 int_ceildiv(OPJ_INT32 a, OPJ_INT32 b) { + return (a + b - 1) / b; +} + +/** +Divide an integer and round upwards +@return Returns a divided by b +*/ +static INLINE OPJ_UINT32 uint_ceildiv(OPJ_UINT32 a, OPJ_UINT32 b) { return (a + b - 1) / b; } /** Divide an integer by a power of 2 and round upwards @return Returns a divided by 2^b */ -static INLINE int int_ceildivpow2(int a, int b) { +static INLINE OPJ_INT32 int_ceildivpow2(OPJ_INT32 a, OPJ_INT32 b) { return (a + (1 << b) - 1) >> b; } /** Divide an integer by a power of 2 and round downwards @return Returns a divided by 2^b */ -static INLINE int int_floordivpow2(int a, int b) { +static INLINE OPJ_INT32 int_floordivpow2(OPJ_INT32 a, OPJ_INT32 b) { return a >> b; } /** Get logarithm of an integer and round downwards @return Returns log2(a) */ -static INLINE int int_floorlog2(int a) { - int l; +static INLINE OPJ_INT32 int_floorlog2(OPJ_INT32 a) { + OPJ_INT32 l; for (l = 0; a > 1; l++) { a >>= 1; } 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/invert.c b/libopenjpeg/invert.c new file mode 100644 index 00000000..1fce6d7a --- /dev/null +++ b/libopenjpeg/invert.c @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "invert.h" +#include "opj_malloc.h" + + +bool opj_lupDecompose(OPJ_FLOAT32 * matrix,OPJ_UINT32 * permutations, OPJ_FLOAT32 * p_swap_area,OPJ_UINT32 n); +void opj_lupSolve(OPJ_FLOAT32 * pResult, OPJ_FLOAT32* pMatrix, OPJ_FLOAT32* pVector, OPJ_UINT32* pPermutations, OPJ_UINT32 n,OPJ_FLOAT32 * p_intermediate_data); +void opj_lupInvert (OPJ_FLOAT32 * pSrcMatrix, + OPJ_FLOAT32 * pDestMatrix, + OPJ_UINT32 n, + OPJ_UINT32 * pPermutations, + OPJ_FLOAT32 * p_src_temp, + OPJ_FLOAT32 * p_dest_temp, + OPJ_FLOAT32 * p_swap_area); + +/** + * Matrix inversion. + */ +bool opj_matrix_inversion_f(OPJ_FLOAT32 * pSrcMatrix,OPJ_FLOAT32 * pDestMatrix, OPJ_UINT32 n) +{ + OPJ_BYTE * l_data = 00; + OPJ_UINT32 l_permutation_size = n * sizeof(OPJ_UINT32); + OPJ_UINT32 l_swap_size = n * sizeof(OPJ_FLOAT32); + OPJ_UINT32 l_total_size = l_permutation_size + 3 * l_swap_size; + OPJ_UINT32 * lPermutations = 00; + OPJ_FLOAT32 * l_double_data = 00; + + l_data = (OPJ_BYTE *) opj_malloc(l_total_size); + if + (l_data == 0) + { + return false; + } + lPermutations = (OPJ_UINT32 *) l_data; + l_double_data = (OPJ_FLOAT32 *) (l_data + l_permutation_size); + memset(lPermutations,0,l_permutation_size); + + if + (! opj_lupDecompose(pSrcMatrix,lPermutations,l_double_data,n)) + { + opj_free(l_data); + return false; + } + opj_lupInvert(pSrcMatrix,pDestMatrix,n,lPermutations,l_double_data,l_double_data + n,l_double_data + 2*n); + opj_free(l_data); + return true; +} + + +/** + * LUP decomposition + */ +bool opj_lupDecompose(OPJ_FLOAT32 * matrix,OPJ_UINT32 * permutations, OPJ_FLOAT32 * p_swap_area,OPJ_UINT32 n) +{ + OPJ_UINT32 * tmpPermutations = permutations; + OPJ_UINT32 * dstPermutations; + OPJ_UINT32 k2=0,t; + OPJ_FLOAT32 temp; + OPJ_UINT32 i,j,k; + OPJ_FLOAT32 p; + OPJ_UINT32 lLastColum = n - 1; + OPJ_UINT32 lSwapSize = n * sizeof(OPJ_FLOAT32); + OPJ_FLOAT32 * lTmpMatrix = matrix; + OPJ_FLOAT32 * lColumnMatrix,* lDestMatrix; + OPJ_UINT32 offset = 1; + OPJ_UINT32 lStride = n-1; + + //initialize permutations + for + (i = 0; i < n; ++i) + { + *tmpPermutations++ = i; + } + + + + // now make a pivot with colum switch + tmpPermutations = permutations; + for + (k = 0; k < lLastColum; ++k) + { + p = 0.0; + + // take the middle element + lColumnMatrix = lTmpMatrix + k; + + // make permutation with the biggest value in the column + for + (i = k; i < n; ++i) + { + temp = ((*lColumnMatrix > 0) ? *lColumnMatrix : -(*lColumnMatrix)); + if + (temp > p) + { + p = temp; + k2 = i; + } + // next line + lColumnMatrix += n; + } + + // a whole rest of 0 -> non singular + if + (p == 0.0) + { + return false; + } + + // should we permute ? + if + (k2 != k) + { + //exchange of line + // k2 > k + dstPermutations = tmpPermutations + k2 - k; + // swap indices + t = *tmpPermutations; + *tmpPermutations = *dstPermutations; + *dstPermutations = t; + + // and swap entire line. + lColumnMatrix = lTmpMatrix + (k2 - k) * n; + memcpy(p_swap_area,lColumnMatrix,lSwapSize); + memcpy(lColumnMatrix,lTmpMatrix,lSwapSize); + memcpy(lTmpMatrix,p_swap_area,lSwapSize); + } + + // now update data in the rest of the line and line after + lDestMatrix = lTmpMatrix + k; + lColumnMatrix = lDestMatrix + n; + // take the middle element + temp = *(lDestMatrix++); + + // now compute up data (i.e. coeff up of the diagonal). + for (i = offset; i < n; ++i) + { + //lColumnMatrix; + // divide the lower column elements by the diagonal value + + // matrix[i][k] /= matrix[k][k]; + // p = matrix[i][k] + p = *lColumnMatrix / temp; + *(lColumnMatrix++) = p; + for + (j = /* k + 1 */ offset; j < n; ++j) + { + // matrix[i][j] -= matrix[i][k] * matrix[k][j]; + *(lColumnMatrix++) -= p * (*(lDestMatrix++)); + } + // come back to the k+1th element + lDestMatrix -= lStride; + // go to kth element of the next line + lColumnMatrix += k; + } + // offset is now k+2 + ++offset; + // 1 element less for stride + --lStride; + // next line + lTmpMatrix+=n; + // next permutation element + ++tmpPermutations; + } + return true; +} + + + +/** + * LUP solving + */ +void opj_lupSolve (OPJ_FLOAT32 * pResult, OPJ_FLOAT32 * pMatrix, OPJ_FLOAT32 * pVector, OPJ_UINT32* pPermutations, OPJ_UINT32 n,OPJ_FLOAT32 * p_intermediate_data) +{ + OPJ_UINT32 i,j; + OPJ_FLOAT32 sum; + OPJ_FLOAT32 u; + OPJ_UINT32 lStride = n+1; + OPJ_FLOAT32 * lCurrentPtr; + OPJ_FLOAT32 * lIntermediatePtr; + OPJ_FLOAT32 * lDestPtr; + OPJ_FLOAT32 * lTmpMatrix; + OPJ_FLOAT32 * lLineMatrix = pMatrix; + OPJ_FLOAT32 * lBeginPtr = pResult + n - 1; + OPJ_FLOAT32 * lGeneratedData; + OPJ_UINT32 * lCurrentPermutationPtr = pPermutations; + + + lIntermediatePtr = p_intermediate_data; + lGeneratedData = p_intermediate_data + n - 1; + + for + (i = 0; i < n; ++i) + { + sum = 0.0; + lCurrentPtr = p_intermediate_data; + lTmpMatrix = lLineMatrix; + for + (j = 1; j <= i; ++j) + { + // sum += matrix[i][j-1] * y[j-1]; + sum += (*(lTmpMatrix++)) * (*(lCurrentPtr++)); + } + //y[i] = pVector[pPermutations[i]] - sum; + *(lIntermediatePtr++) = pVector[*(lCurrentPermutationPtr++)] - sum; + lLineMatrix += n; + } + + // we take the last point of the matrix + lLineMatrix = pMatrix + n*n - 1; + + // and we take after the last point of the destination vector + lDestPtr = pResult + n; + + for + (i = n - 1; i != -1 ; --i) + { + sum = 0.0; + lTmpMatrix = lLineMatrix; + u = *(lTmpMatrix++); + lCurrentPtr = lDestPtr--; + for + (j = i + 1; j < n; ++j) + { + // sum += matrix[i][j] * x[j] + sum += (*(lTmpMatrix++)) * (*(lCurrentPtr++)); + } + //x[i] = (y[i] - sum) / u; + *(lBeginPtr--) = (*(lGeneratedData--) - sum) / u; + lLineMatrix -= lStride; + } +} + +/** LUP inversion (call with the result of lupDecompose) + */ +void opj_lupInvert ( + OPJ_FLOAT32 * pSrcMatrix, + OPJ_FLOAT32 * pDestMatrix, + OPJ_UINT32 n, + OPJ_UINT32 * pPermutations, + OPJ_FLOAT32 * p_src_temp, + OPJ_FLOAT32 * p_dest_temp, + OPJ_FLOAT32 * p_swap_area + ) +{ + OPJ_UINT32 j,i; + OPJ_FLOAT32 * lCurrentPtr; + OPJ_FLOAT32 * lLineMatrix = pDestMatrix; + OPJ_UINT32 lSwapSize = n * sizeof(OPJ_FLOAT32); + + for + (j = 0; j < n; ++j) + { + lCurrentPtr = lLineMatrix++; + memset(p_src_temp,0,lSwapSize); + p_src_temp[j] = 1.0; + opj_lupSolve(p_dest_temp,pSrcMatrix,p_src_temp, pPermutations, n , p_swap_area); + + for + (i = 0; i < n; ++i) + { + *(lCurrentPtr) = p_dest_temp[i]; + lCurrentPtr+=n; + } + } +} + diff --git a/libopenjpeg/invert.h b/libopenjpeg/invert.h new file mode 100644 index 00000000..8a39d363 --- /dev/null +++ b/libopenjpeg/invert.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __INVERT_H +#define __INVERT_H +#include "openjpeg.h" +/** + * Calculates a n x n double matrix inversion with a LUP method. Data is aligned, rows after rows (or columns after columns). + * The function does not take ownership of any memory block, data must be fred by the user. + * + * @param pSrcMatrix the matrix to invert. + * @param pDestMatrix data to store the inverted matrix. + * @return 1 if the inversion is successful, 0 if the matrix is singular. + */ +bool opj_matrix_inversion_f(OPJ_FLOAT32 * pSrcMatrix,OPJ_FLOAT32 * pDestMatrix, OPJ_UINT32 n); +#endif + diff --git a/libopenjpeg/j2k.c b/libopenjpeg/j2k.c index 563efd68..451d57e0 100644 --- a/libopenjpeg/j2k.c +++ b/libopenjpeg/j2k.c @@ -6,6 +6,7 @@ * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe * Copyright (c) 2005, Herve Drolon, FreeImage Team * Copyright (c) 2006-2007, Parvatha Elangovan + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,216 +31,1224 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include "j2k.h" +#include "opj_malloc.h" #include "opj_includes.h" +#include "pi.h" +#include "event.h" +#include "cio.h" +#include "int.h" +#include "tcd.h" +#include "function_list.h" +#include "invert.h" +#include "dwt.h" +#include "mct.h" +#include "image.h" /** @defgroup J2K J2K - JPEG-2000 codestream reader/writer */ /*@{*/ + +/*************************************************************************** + ********************** TYPEDEFS ******************************************* + ***************************************************************************/ +/** + * Correspondance prog order <-> string representation + */ +typedef struct j2k_prog_order +{ + OPJ_PROG_ORDER enum_prog; + OPJ_CHAR str_prog[4]; +} +j2k_prog_order_t; + +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 */ + bool (*handler) ( + opj_j2k_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; + + + /** @name Local static functions */ /*@{*/ +/** + * Writes a SPCod or SPCoc element, i.e. the coding style of a given component of a tile. + * + * @param p_comp_no the component number to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. + * +*/ +static bool j2k_write_SPCod_SPCoc( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_header_size, + struct opj_event_mgr * p_manager + ); /** -Write the SOC marker (Start Of Codestream) -@param j2k J2K handle + * 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 void j2k_write_soc(opj_j2k_t *j2k); +static bool j2k_read_SPCod_SPCoc( + opj_j2k_t *p_j2k, + OPJ_UINT32 compno, + OPJ_BYTE * p_header_data, + OPJ_UINT32 * p_header_size, + struct opj_event_mgr * p_manager + ); + /** -Read the SOC marker (Start of Codestream) -@param j2k J2K handle + * Gets the size taken by writting a SPCod or SPCoc for the given tile and component. + * + * @param p_tile_no the tile indix. + * @param p_comp_no the component being outputted. + * @param p_j2k the J2K codec. + * + * @return the number of bytes taken by the SPCod element. + */ +static OPJ_UINT32 j2k_get_SPCod_SPCoc_size ( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no + ); + +/** + * Writes a SQcd or SQcc element, i.e. the quantization values of a band in the QCD or QCC. + * + * @param p_tile_no the tile to output. + * @param p_comp_no the component number to output. + * @param p_data the data buffer. + * @param p_header_size pointer to the size of the data buffer, it is changed by the function. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. + * */ -static void j2k_read_soc(opj_j2k_t *j2k); +static bool j2k_write_SQcd_SQcc( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_header_size, + struct opj_event_mgr * p_manager + ); + /** -Write the SIZ marker (image and tile size) -@param j2k J2K handle + * 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 void j2k_write_siz(opj_j2k_t *j2k); +static bool j2k_read_SQcd_SQcc( + opj_j2k_t *p_j2k, + OPJ_UINT32 compno, + OPJ_BYTE * p_header_data, + OPJ_UINT32 * p_header_size, + struct opj_event_mgr * p_manager + ); +/** + * Updates the Tile Length Marker. + */ +static void j2k_update_tlm ( + opj_j2k_t * p_j2k, + OPJ_UINT32 p_tile_part_size); + +/** + * Gets the size taken by writting SQcd or SQcc element, i.e. the quantization values of a band in the QCD or QCC. + * + * @param p_tile_no the tile indix. + * @param p_comp_no the component being outputted. + * @param p_j2k the J2K codec. + * + * @return the number of bytes taken by the SPCod element. + */ +static OPJ_UINT32 j2k_get_SQcd_SQcc_size ( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no + + ); + +/** + * 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_t *p_j2k + ); + /** -Read the SIZ marker (image and tile size) -@param j2k J2K handle + * Writes the SOC marker (Start Of Codestream) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. */ -static void j2k_read_siz(opj_j2k_t *j2k); + +static bool j2k_write_soc( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); /** -Write the COM marker (comment) -@param j2k J2K handle + * 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 void j2k_write_com(opj_j2k_t *j2k); +static bool j2k_read_soc( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); /** -Read the COM marker (comment) -@param j2k J2K handle + * Writes the SIZ marker (image and tile size) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. */ -static void j2k_read_com(opj_j2k_t *j2k); +static bool j2k_write_siz( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); /** -Write the value concerning the specified component in the marker COD and COC -@param j2k J2K handle -@param compno Number of the component concerned by the information written + * Writes the CBD-MCT-MCC-MCO markers (Multi components transform) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. */ -static void j2k_write_cox(opj_j2k_t *j2k, int compno); +static bool j2k_write_mct_data_group( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); + /** -Read the value concerning the specified component in the marker COD and COC -@param j2k J2K handle -@param compno Number of the component concerned by the information read + * 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 void j2k_read_cox(opj_j2k_t *j2k, int compno); +static bool j2k_read_siz ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); /** -Write the COD marker (coding style default) -@param j2k J2K handle + * Writes the COM marker (comment) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. */ -static void j2k_write_cod(opj_j2k_t *j2k); +static bool j2k_write_com( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); /** -Read the COD marker (coding style default) -@param j2k J2K handle + * 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 void j2k_read_cod(opj_j2k_t *j2k); +static bool j2k_read_com ( + opj_j2k_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 -@param compno Number of the component concerned by the information written + * Writes the COD marker (Coding style default) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. */ -static void j2k_write_coc(opj_j2k_t *j2k, int compno); +static bool j2k_write_cod( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); /** -Read the COC marker (coding style component) -@param j2k J2K handle + * 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 void j2k_read_coc(opj_j2k_t *j2k); +static bool j2k_read_cod ( + opj_j2k_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 -@param compno Number of the component concerned by the information written + * Writes the COC marker (Coding style component) + * + * @param p_comp_number the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. */ -static void j2k_write_qcx(opj_j2k_t *j2k, int compno); +static bool j2k_write_coc( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_comp_number, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); + /** -Read the value concerning the specified component in the marker QCD and QCC -@param j2k J2K handle -@param compno Number of the component concern by the information read -@param len Length of the information in the QCX part of the marker QCD/QCC + * Writes the COC marker (Coding style component) + * + * @param p_comp_no the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. */ -static void j2k_read_qcx(opj_j2k_t *j2k, int compno, int len); +static void j2k_write_coc_in_memory( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_comp_no, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + struct opj_event_mgr * p_manager + ); +/** + * Gets the maximum size taken by a coc. + * + * @param p_j2k the jpeg2000 codec to use. + */ +static OPJ_UINT32 j2k_get_max_coc_size(opj_j2k_t *p_j2k); + /** -Write the QCD marker (quantization default) -@param j2k J2K handle + * 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 void j2k_write_qcd(opj_j2k_t *j2k); +static bool j2k_read_coc ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); + /** -Read the QCD marker (quantization default) -@param j2k J2K handle + * Writes the QCD marker (quantization default) + * + * @param p_comp_number the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. */ -static void j2k_read_qcd(opj_j2k_t *j2k); +static bool j2k_write_qcd( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); + + /** -Write the QCC marker (quantization component) -@param j2k J2K handle -@param compno Number of the component concerned by the information written + * 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 void j2k_write_qcc(opj_j2k_t *j2k, int compno); +static bool j2k_read_qcd ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); /** -Read the QCC marker (quantization component) -@param j2k J2K handle + * Writes the QCC marker (quantization component) + * + * @param p_comp_no the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. */ -static void j2k_read_qcc(opj_j2k_t *j2k); +static bool j2k_write_qcc( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_comp_no, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); /** -Write the POC marker (progression order change) -@param j2k J2K handle + * Writes the QCC marker (quantization component) + * + * @param p_comp_no the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. */ -static void j2k_write_poc(opj_j2k_t *j2k); +static void j2k_write_qcc_in_memory( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_comp_no, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + struct opj_event_mgr * p_manager + ); +/** + * Gets the maximum size taken by a qcc. + */ +static OPJ_UINT32 j2k_get_max_qcc_size (opj_j2k_t *p_j2k); + /** -Read the POC marker (progression order change) -@param j2k J2K handle + * 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 void j2k_read_poc(opj_j2k_t *j2k); +static bool j2k_read_qcc( + opj_j2k_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 + * Writes the POC marker (Progression Order Change) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. */ -static void j2k_read_crg(opj_j2k_t *j2k); +static bool j2k_write_poc( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); + /** -Read the TLM marker (tile-part lengths) -@param j2k J2K handle + * Writes the updated tlm. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. */ -static void j2k_read_tlm(opj_j2k_t *j2k); +static bool j2k_write_updated_tlm( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); + +/** + * Writes the POC marker (Progression Order Change) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. + */ +static void j2k_write_poc_in_memory( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + struct opj_event_mgr * p_manager + ); + /** -Read the PLM marker (packet length, main header) -@param j2k J2K handle + * Gets the maximum size taken by the writting of a POC. + */ +static OPJ_UINT32 j2k_get_max_poc_size(opj_j2k_t *p_j2k); + +/** + * Gets the maximum size taken by the toc headers of all the tile parts of any given tile. + */ +static OPJ_UINT32 j2k_get_max_toc_size (opj_j2k_t *p_j2k); + +/** + * Gets the maximum size taken by the headers of the SOT. + * + * @param p_j2k the jpeg2000 codec to use. + */ +static OPJ_UINT32 j2k_get_specific_header_sizes(opj_j2k_t *p_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 bool j2k_read_poc ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); +/** + * 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 bool j2k_read_crg ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); +/** + * 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 bool j2k_read_tlm ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); +/** + * 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 void j2k_read_plm(opj_j2k_t *j2k); +static bool j2k_read_plm ( + opj_j2k_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 + * 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 void j2k_read_plt(opj_j2k_t *j2k); +static bool j2k_read_plt ( + opj_j2k_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 + * 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 void j2k_read_ppm(opj_j2k_t *j2k); +static bool j2k_read_ppm ( + opj_j2k_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 + * 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 void j2k_read_ppt(opj_j2k_t *j2k); +static bool j2k_read_ppt ( + opj_j2k_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 + * Writes the TLM marker (Tile Length Marker) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. */ -static void j2k_write_tlm(opj_j2k_t *j2k); +static bool j2k_write_tlm( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); /** -Write the SOT marker (start of tile-part) -@param j2k J2K handle + * Writes the SOT marker (Start of tile-part) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. */ -static void j2k_write_sot(opj_j2k_t *j2k); +static bool j2k_write_sot( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + const struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); /** -Read the SOT marker (start of tile-part) -@param j2k J2K handle + * 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 void j2k_read_sot(opj_j2k_t *j2k); +static bool j2k_read_sot ( + opj_j2k_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 -@param tile_coder Pointer to a TCD handle + * Writes the SOD marker (Start of data) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. */ -static void j2k_write_sod(opj_j2k_t *j2k, void *tile_coder); +static bool j2k_write_sod( + opj_j2k_t *p_j2k, + struct opj_tcd * p_tile_coder, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 p_total_data_size, + const struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); /** -Read the SOD marker (start of data) -@param j2k J2K handle + * 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. */ -static void j2k_read_sod(opj_j2k_t *j2k); +static bool j2k_read_sod ( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); /** -Write the RGN marker (region-of-interest) -@param j2k J2K handle -@param compno Number of the component concerned by the information written -@param tileno Number of the tile concerned by the information written + * Writes the RGN marker (Region Of Interest) + * + * @param p_tile_no the tile to output + * @param p_comp_no the component to output + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. */ -static void j2k_write_rgn(opj_j2k_t *j2k, int compno, int tileno); +static bool j2k_write_rgn( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); /** -Read the RGN marker (region-of-interest) -@param j2k J2K handle + * 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 void j2k_read_rgn(opj_j2k_t *j2k); +static bool j2k_read_rgn ( + opj_j2k_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 + * Writes the EOC marker (End of Codestream) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. */ -static void j2k_write_eoc(opj_j2k_t *j2k); +static bool j2k_write_eoc( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); + /** -Read the EOC marker (end of codestream) -@param j2k J2K handle + * 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_quantization_parameters( + opj_j2k_t *p_j2k + ); + +/** + * Reads a EOC marker (End Of Codestream) + * + * @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. */ -static void j2k_read_eoc(opj_j2k_t *j2k); +static bool j2k_read_eoc ( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) ; + /** -Read an unknown marker -@param j2k J2K handle + * Inits the Info + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. */ -static void j2k_read_unk(opj_j2k_t *j2k); +static bool j2k_init_info( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); +/** + * Reads an unknown marker + * + * @param p_stream the stream object to read from. + * @param p_j2k the jpeg2000 codec. + * @param p_manager the user event manager. + * + * @return true if the marker could be deduced. +*/ +static bool j2k_read_unk ( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); +/** + * Ends the encoding, i.e. frees memory. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_end_encoding( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); + +/** + * Writes the CBD marker (Component bit depth definition) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_write_cbd( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); + +/** + * Reads a CBD marker (Component bit depth definition) + * @param p_header_data the data contained in the CBD box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the CBD marker. + * @param p_manager the user event manager. +*/ +static bool j2k_read_cbd ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager); + +/** + * Writes the MCT marker (Multiple Component Transform) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_write_mct_record( + opj_j2k_t *p_j2k, + opj_mct_data_t * p_mct_record, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); + +/** + * Reads a MCT marker (Multiple Component Transform) + * + * @param p_header_data the data contained in the MCT box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the MCT marker. + * @param p_manager the user event manager. +*/ +static bool j2k_read_mct ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); + +/** + * Writes the MCC marker (Multiple Component Collection) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_write_mcc_record( + opj_j2k_t *p_j2k, + struct opj_simple_mcc_decorrelation_data * p_mcc_record, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); + +/** + * Reads a MCC marker (Multiple Component Collection) + * + * @param p_header_data the data contained in the MCC box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the MCC marker. + * @param p_manager the user event manager. +*/ +static bool j2k_read_mcc ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); + +/** + * Writes the MCO marker (Multiple component transformation ordering) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_write_mco( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); + +/** + * Reads a MCO marker (Multiple Component Transform Ordering) + * + * @param p_header_data the data contained in the MCO box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the MCO marker. + * @param p_manager the user event manager. +*/ +static bool j2k_read_mco ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); +/** + * Writes the image components. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_write_image_components( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); + +/** + * Writes regions of interests. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_write_regions( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); +/** + * Writes EPC ???? + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_write_epc( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); + +/** + * Checks the progression order changes values. Tells of the poc given as input are valid. + * A nice message is outputted at errors. + * + * @param p_pocs the progression order changes. + * @param p_nb_pocs the number of progression order changes. + * @param p_nb_resolutions the number of resolutions. + * @param numcomps the number of components + * @param numlayers the number of layers. + * + * @return true if the pocs are valid. + */ +static bool j2k_check_poc_val( + const opj_poc_t *p_pocs, + OPJ_UINT32 p_nb_pocs, + OPJ_UINT32 p_nb_resolutions, + OPJ_UINT32 numcomps, + OPJ_UINT32 numlayers, + opj_event_mgr_t * p_manager); + +/** + * Gets the number of tile parts used for the given change of progression (if any) and the given tile. + * + * @param cp the coding parameters. + * @param pino the offset of the given poc (i.e. its position in the coding parameter). + * @param tileno the given tile. + * + * @return the number of tile parts. + */ +static OPJ_UINT32 j2k_get_num_tp( + opj_cp_t *cp, + OPJ_UINT32 pino, + OPJ_UINT32 tileno); +/** + * Calculates the total number of tile parts needed by the encoder to + * encode such an image. If not enough memory is available, then the function return false. + * + * @param p_nb_tiles pointer that will hold the number of tile parts. + * @param cp the coding parameters for the image. + * @param image the image to encode. + * @param p_j2k the p_j2k encoder. + * @param p_manager the user event manager. + * + * @return true if the function was successful, false else. + */ +static bool j2k_calculate_tp( + opj_j2k_t *p_j2k, + opj_cp_t *cp, + OPJ_UINT32 * p_nb_tiles, + opj_image_t *image, + opj_event_mgr_t * p_manager); + +static bool j2k_write_first_tile_part ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 p_total_data_size, + opj_stream_private_t *p_stream, + struct opj_event_mgr * p_manager + ); +static bool j2k_write_all_tile_parts( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 p_total_data_size, + opj_stream_private_t *p_stream, + struct opj_event_mgr * 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_t *p_tcp); + +static void j2k_get_tile_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data); + +/** + * Destroys a coding parameter structure. + * + * @param p_cp the coding parameter to destroy. + */ +static void j2k_cp_destroy (opj_cp_t *p_cp); + +/** + * Sets up the validation ,i.e. adds the procedures to lauch to make sure the codec parameters + * are valid. Developpers wanting to extend the library can add their own validation procedures. + */ +static void j2k_setup_encoding_validation (opj_j2k_t *p_j2k); + +/** + * Sets up the validation ,i.e. adds the procedures to lauch to make sure the codec parameters + * are valid. Developpers wanting to extend the library can add their own validation procedures. + */ +static void j2k_setup_decoding_validation (opj_j2k_t *p_j2k); + +/** + * Sets up the validation ,i.e. adds the procedures to lauch to make sure the codec parameters + * are valid. Developpers wanting to extend the library can add their own validation procedures. + */ +static void j2k_setup_end_compress (opj_j2k_t *p_j2k); + +/** + * Creates a tile-coder decoder. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_create_tcd( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); + +/** + * Excutes the given procedures on the given codec. + * + * @param p_procedure_list the list of procedures to execute + * @param p_j2k the jpeg2000 codec to execute the procedures on. + * @param p_stream the stream to execute the procedures on. + * @param p_manager the user manager. + * + * @return true if all the procedures were successfully executed. + */ +static bool j2k_exec ( + opj_j2k_t * p_j2k, + opj_procedure_list_t * p_procedure_list, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ); +/** + * Updates the rates of the tcp. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_update_rates( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); + +/** + * The default encoding validation procedure without any extension. + * + * @param p_j2k the jpeg2000 codec to validate. + * @param p_stream the input stream to validate. + * @param p_manager the user event manager. + * + * @return true if the parameters are correct. + */ +bool j2k_encoding_validation ( + opj_j2k_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ); +/** + * The read header procedure. + */ +bool j2k_read_header_procedure( + opj_j2k_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. + */ +bool j2k_decoding_validation ( + opj_j2k_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ); +/** + * Reads the tiles. + */ +bool j2k_decode_tiles ( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager); + +/** + * The mct encoding validation procedure. + * + * @param p_j2k the jpeg2000 codec to validate. + * @param p_stream the input stream to validate. + * @param p_manager the user event manager. + * + * @return true if the parameters are correct. + */ +bool j2k_mct_validation ( + opj_j2k_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ); +/** + * Builds the tcd decoder to use to decode tile. + */ +bool j2k_build_decoder ( + opj_j2k_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ); +/** + * Builds the tcd encoder to use to encode tile. + */ +bool j2k_build_encoder ( + opj_j2k_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ); +/** + * Copies the decoding tile parameters onto all the tile parameters. + * Creates also the tile decoder. + */ +bool j2k_copy_default_tcp_and_create_tcd( + opj_j2k_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ); +/** + * Destroys the memory associated with the decoding of headers. + */ +bool j2k_destroy_header_memory ( + opj_j2k_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ); + +/** + * Sets up the procedures to do on writting header. Developpers wanting to extend the library can add their own writting procedures. + */ +void j2k_setup_header_writting (opj_j2k_t *p_j2k); + +/** + * 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_t *p_j2k); + +/** + * Writes a tile. + * @param p_j2k the jpeg2000 codec. + * @param p_stream the stream to write data to. + * @param p_manager the user event manager. + */ +static bool j2k_post_write_tile ( + opj_j2k_t * p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 p_data_size, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ); + +static bool j2k_pre_write_tile ( + opj_j2k_t * p_j2k, + OPJ_UINT32 p_tile_index, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ); +static bool j2k_update_image_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data); + +static bool j2k_add_mct(opj_tcp_t * p_tcp,opj_image_t * p_image, OPJ_UINT32 p_index); +/** + * Gets the offset of the header. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_get_end_header( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); + +static void j2k_read_int16_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem); +static void j2k_read_int32_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem); +static void j2k_read_float32_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem); +static void j2k_read_float64_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem); + +static void j2k_read_int16_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem); +static void j2k_read_int32_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem); +static void j2k_read_float32_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem); +static void j2k_read_float64_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem); + +static void j2k_write_float_to_int16 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem); +static void j2k_write_float_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem); +static void j2k_write_float_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem); +static void j2k_write_float_to_float64 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem); + + /*@}*/ /*@}*/ /* ----------------------------------------------------------------------- */ -typedef struct j2k_prog_order{ - OPJ_PROG_ORDER enum_prog; - char str_prog[4]; -}j2k_prog_order_t; -j2k_prog_order_t j2k_prog_order_list[] = { + + +/**************************************************************************** + ********************* CONSTANTS ******************************************** + ****************************************************************************/ + + + + +/** + * List of progression orders. + */ +const j2k_prog_order_t j2k_prog_order_list [] = +{ {CPRL, "CPRL"}, {LRCP, "LRCP"}, {PCRL, "PCRL"}, @@ -248,264 +1257,884 @@ j2k_prog_order_t j2k_prog_order_list[] = { {-1, ""} }; -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++ ){ - if(po->enum_prog == prg_order){ - break; +const OPJ_UINT32 MCT_ELEMENT_SIZE [] = +{ + 2, + 4, + 4, + 8 +}; + +typedef void (* j2k_mct_function) (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem); + +const j2k_mct_function j2k_mct_read_functions_to_float [] = +{ + j2k_read_int16_to_float, + j2k_read_int32_to_float, + j2k_read_float32_to_float, + j2k_read_float64_to_float +}; + +const j2k_mct_function j2k_mct_read_functions_to_int32 [] = +{ + j2k_read_int16_to_int32, + j2k_read_int32_to_int32, + j2k_read_float32_to_int32, + j2k_read_float64_to_int32 +}; + +const j2k_mct_function j2k_mct_write_functions_from_float [] = +{ + j2k_write_float_to_int16, + j2k_write_float_to_int32, + j2k_write_float_to_float, + j2k_write_float_to_float64 +}; + + + + +/*const opj_dec_stream_marker_handler_t j2k_stream_marker_handler_tab[] = +{ + {J2K_MS_SOC, J2K_DEC_STATE_MHSOC, j2k_read_soc}, + {J2K_MS_SOD, J2K_DEC_STATE_TPH, j2k_read_sod}, + {J2K_MS_EOC, J2K_DEC_STATE_TPHSOT, j2k_read_eoc}, + {J2K_MS_SOP, 0, 0}, +#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 +#ifdef USE_JPSEC + {J2K_MS_SEC, J2K_DEC_STATE_MH, j2k_read_sec}, + {J2K_MS_INSEC, 0, j2k_read_insec}, +#endif + + {0, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPH, j2k_read_unk} +};*/ + +const opj_dec_memory_marker_handler_t j2k_memory_marker_handler_tab [] = +{ + {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} +#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 */ +}; + +void j2k_read_int16_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) +{ + OPJ_BYTE * l_src_data = (OPJ_BYTE *) p_src_data; + OPJ_FLOAT32 * l_dest_data = (OPJ_FLOAT32 *) p_dest_data; + OPJ_UINT32 i; + OPJ_UINT32 l_temp; + + for + (i=0;i<p_nb_elem;++i) + { + opj_read_bytes(l_src_data,&l_temp,2); + l_src_data+=sizeof(OPJ_INT16); + *(l_dest_data++) = (OPJ_FLOAT32) l_temp; + } +} + +void j2k_read_int32_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) +{ + OPJ_BYTE * l_src_data = (OPJ_BYTE *) p_src_data; + OPJ_FLOAT32 * l_dest_data = (OPJ_FLOAT32 *) p_dest_data; + OPJ_UINT32 i; + OPJ_UINT32 l_temp; + + for + (i=0;i<p_nb_elem;++i) + { + opj_read_bytes(l_src_data,&l_temp,4); + l_src_data+=sizeof(OPJ_INT32); + *(l_dest_data++) = (OPJ_FLOAT32) l_temp; + } +} +void j2k_read_float32_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) +{ + OPJ_BYTE * l_src_data = (OPJ_BYTE *) p_src_data; + OPJ_FLOAT32 * l_dest_data = (OPJ_FLOAT32 *) p_dest_data; + OPJ_UINT32 i; + OPJ_FLOAT32 l_temp; + + for + (i=0;i<p_nb_elem;++i) + { + opj_read_float(l_src_data,&l_temp); + l_src_data+=sizeof(OPJ_FLOAT32); + *(l_dest_data++) = l_temp; + } +} + +void j2k_read_float64_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) +{ + OPJ_BYTE * l_src_data = (OPJ_BYTE *) p_src_data; + OPJ_FLOAT32 * l_dest_data = (OPJ_FLOAT32 *) p_dest_data; + OPJ_UINT32 i; + OPJ_FLOAT64 l_temp; + + for + (i=0;i<p_nb_elem;++i) + { + opj_read_double(l_src_data,&l_temp); + l_src_data+=sizeof(OPJ_FLOAT64); + *(l_dest_data++) = (OPJ_FLOAT32) l_temp; + } + +} + +void j2k_read_int16_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) +{ + OPJ_BYTE * l_src_data = (OPJ_BYTE *) p_src_data; + OPJ_INT32 * l_dest_data = (OPJ_INT32 *) p_dest_data; + OPJ_UINT32 i; + OPJ_UINT32 l_temp; + + for + (i=0;i<p_nb_elem;++i) + { + opj_read_bytes(l_src_data,&l_temp,2); + l_src_data+=sizeof(OPJ_INT16); + *(l_dest_data++) = (OPJ_INT32) l_temp; + } +} + +void j2k_read_int32_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) +{ + OPJ_BYTE * l_src_data = (OPJ_BYTE *) p_src_data; + OPJ_INT32 * l_dest_data = (OPJ_INT32 *) p_dest_data; + OPJ_UINT32 i; + OPJ_UINT32 l_temp; + + for + (i=0;i<p_nb_elem;++i) + { + opj_read_bytes(l_src_data,&l_temp,4); + l_src_data+=sizeof(OPJ_INT32); + *(l_dest_data++) = (OPJ_INT32) l_temp; + } +} +void j2k_read_float32_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) +{ + OPJ_BYTE * l_src_data = (OPJ_BYTE *) p_src_data; + OPJ_INT32 * l_dest_data = (OPJ_INT32 *) p_dest_data; + OPJ_UINT32 i; + OPJ_FLOAT32 l_temp; + + for + (i=0;i<p_nb_elem;++i) + { + opj_read_float(l_src_data,&l_temp); + l_src_data+=sizeof(OPJ_FLOAT32); + *(l_dest_data++) = (OPJ_INT32) l_temp; + } +} + +void j2k_read_float64_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) +{ + OPJ_BYTE * l_src_data = (OPJ_BYTE *) p_src_data; + OPJ_INT32 * l_dest_data = (OPJ_INT32 *) p_dest_data; + OPJ_UINT32 i; + OPJ_FLOAT64 l_temp; + + for + (i=0;i<p_nb_elem;++i) + { + opj_read_double(l_src_data,&l_temp); + l_src_data+=sizeof(OPJ_FLOAT64); + *(l_dest_data++) = (OPJ_INT32) l_temp; + } + +} + +void j2k_write_float_to_int16 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) +{ + OPJ_BYTE * l_dest_data = (OPJ_BYTE *) p_dest_data; + OPJ_FLOAT32 * l_src_data = (OPJ_FLOAT32 *) p_src_data; + OPJ_UINT32 i; + OPJ_UINT32 l_temp; + + for + (i=0;i<p_nb_elem;++i) + { + l_temp = (OPJ_UINT32) *(l_src_data++); + opj_write_bytes(l_dest_data,l_temp,sizeof(OPJ_INT16)); + l_dest_data+=sizeof(OPJ_INT16); + } +} + +void j2k_write_float_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) +{ + OPJ_BYTE * l_dest_data = (OPJ_BYTE *) p_dest_data; + OPJ_FLOAT32 * l_src_data = (OPJ_FLOAT32 *) p_src_data; + OPJ_UINT32 i; + OPJ_UINT32 l_temp; + + for + (i=0;i<p_nb_elem;++i) + { + l_temp = (OPJ_UINT32) *(l_src_data++); + opj_write_bytes(l_dest_data,l_temp,sizeof(OPJ_INT32)); + l_dest_data+=sizeof(OPJ_INT32); + } +} + +void j2k_write_float_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) +{ + OPJ_BYTE * l_dest_data = (OPJ_BYTE *) p_dest_data; + OPJ_FLOAT32 * l_src_data = (OPJ_FLOAT32 *) p_src_data; + OPJ_UINT32 i; + OPJ_FLOAT32 l_temp; + + for + (i=0;i<p_nb_elem;++i) + { + l_temp = (OPJ_FLOAT32) *(l_src_data++); + opj_write_float(l_dest_data,l_temp); + l_dest_data+=sizeof(OPJ_FLOAT32); + } + +} + +void j2k_write_float_to_float64 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) +{ + OPJ_BYTE * l_dest_data = (OPJ_BYTE *) p_dest_data; + OPJ_FLOAT32 * l_src_data = (OPJ_FLOAT32 *) p_src_data; + OPJ_UINT32 i; + OPJ_FLOAT64 l_temp; + for + (i=0;i<p_nb_elem;++i) + { + l_temp = (OPJ_FLOAT64) *(l_src_data++); + opj_write_double(l_dest_data,l_temp); + l_dest_data+=sizeof(OPJ_FLOAT64); + } +} + + + + +/** + * Converts an enum type progression order to string type. + * + * @param prg_order the progression order to get. + * + * @return the string representation of the gicen progression order. + */ +const OPJ_CHAR * j2k_convert_progression_order(OPJ_PROG_ORDER p_prg_order) +{ + const j2k_prog_order_t *po; + for + (po = j2k_prog_order_list; po->enum_prog != -1; ++po ) + { + if + (po->enum_prog == p_prg_order) + { + return po->str_prog; } } return po->str_prog; } -void j2k_dump_image(FILE *fd, opj_image_t * img) { - int compno; - fprintf(fd, "image {\n"); - fprintf(fd, " x0=%d, y0=%d, x1=%d, y1=%d\n", img->x0, img->y0, img->x1, img->y1); - fprintf(fd, " numcomps=%d\n", img->numcomps); - for (compno = 0; compno < img->numcomps; compno++) { - opj_image_comp_t *comp = &img->comps[compno]; - fprintf(fd, " comp %d {\n", compno); - fprintf(fd, " dx=%d, dy=%d\n", comp->dx, comp->dy); - fprintf(fd, " prec=%d\n", comp->prec); - fprintf(fd, " sgnd=%d\n", comp->sgnd); - fprintf(fd, " }\n"); - } - fprintf(fd, "}\n"); -} - -void j2k_dump_cp(FILE *fd, opj_image_t * img, opj_cp_t * cp) { - int tileno, compno, layno, bandno, resno, numbands; - fprintf(fd, "coding parameters {\n"); - fprintf(fd, " tx0=%d, ty0=%d\n", cp->tx0, cp->ty0); - fprintf(fd, " tdx=%d, tdy=%d\n", cp->tdx, cp->tdy); - fprintf(fd, " tw=%d, th=%d\n", cp->tw, cp->th); - for (tileno = 0; tileno < cp->tw * cp->th; tileno++) { - opj_tcp_t *tcp = &cp->tcps[tileno]; - fprintf(fd, " tile %d {\n", tileno); - fprintf(fd, " csty=%x\n", tcp->csty); - fprintf(fd, " prg=%d\n", tcp->prg); - fprintf(fd, " numlayers=%d\n", tcp->numlayers); - fprintf(fd, " mct=%d\n", tcp->mct); - fprintf(fd, " rates="); - for (layno = 0; layno < tcp->numlayers; layno++) { - fprintf(fd, "%.1f ", tcp->rates[layno]); - } - fprintf(fd, "\n"); - for (compno = 0; compno < img->numcomps; compno++) { - opj_tccp_t *tccp = &tcp->tccps[compno]; - fprintf(fd, " comp %d {\n", compno); - fprintf(fd, " csty=%x\n", tccp->csty); - fprintf(fd, " numresolutions=%d\n", tccp->numresolutions); - fprintf(fd, " cblkw=%d\n", tccp->cblkw); - fprintf(fd, " cblkh=%d\n", tccp->cblkh); - fprintf(fd, " cblksty=%x\n", tccp->cblksty); - fprintf(fd, " qmfbid=%d\n", tccp->qmfbid); - fprintf(fd, " qntsty=%d\n", tccp->qntsty); - fprintf(fd, " numgbits=%d\n", tccp->numgbits); - fprintf(fd, " roishift=%d\n", tccp->roishift); - fprintf(fd, " stepsizes="); - numbands = tccp->qntsty == J2K_CCP_QNTSTY_SIQNT ? 1 : tccp->numresolutions * 3 - 2; - for (bandno = 0; bandno < numbands; bandno++) { - fprintf(fd, "(%d,%d) ", tccp->stepsizes[bandno].mant, - tccp->stepsizes[bandno].expn); - } - fprintf(fd, "\n"); - - if (tccp->csty & J2K_CCP_CSTY_PRT) { - fprintf(fd, " prcw="); - for (resno = 0; resno < tccp->numresolutions; resno++) { - fprintf(fd, "%d ", tccp->prcw[resno]); - } - fprintf(fd, "\n"); - fprintf(fd, " prch="); - for (resno = 0; resno < tccp->numresolutions; resno++) { - fprintf(fd, "%d ", tccp->prch[resno]); + + + + + + +/** + * Checks the progression order changes values. Tells if the poc given as input are valid. + * + * @param p_pocs the progression order changes. + * @param p_nb_pocs the number of progression order changes. + * @param p_nb_resolutions the number of resolutions. + * @param numcomps the number of components + * @param numlayers the number of layers. + * @param p_manager the user event manager. + * + * @return true if the pocs are valid. + */ +bool j2k_check_poc_val(const opj_poc_t *p_pocs, OPJ_UINT32 p_nb_pocs, OPJ_UINT32 p_nb_resolutions, OPJ_UINT32 p_num_comps, OPJ_UINT32 p_num_layers, opj_event_mgr_t * p_manager) +{ + OPJ_UINT32* packet_array; + OPJ_UINT32 index , resno, compno, layno; + OPJ_UINT32 i; + OPJ_UINT32 step_c = 1; + OPJ_UINT32 step_r = p_num_comps * step_c; + OPJ_UINT32 step_l = p_nb_resolutions * step_r; + bool loss = false; + OPJ_UINT32 layno0 = 0; + + packet_array = (OPJ_UINT32*) opj_calloc(step_l * p_num_layers, sizeof(OPJ_UINT32)); + if + (packet_array == 00) + { + opj_event_msg(p_manager , EVT_ERROR, "Not enough memory for checking the poc values.\n"); + return false; + } + memset(packet_array,0,step_l * p_num_layers* sizeof(OPJ_UINT32)); + if + (p_nb_pocs == 0) + { + return true; + } + + index = step_r * p_pocs->resno0; + // take each resolution for each poc + for + (resno = p_pocs->resno0 ; resno < p_pocs->resno1 ; ++resno) + { + OPJ_UINT32 res_index = index + p_pocs->compno0 * step_c; + // take each comp of each resolution for each poc + for + (compno = p_pocs->compno0 ; compno < p_pocs->compno1 ; ++compno) + { + OPJ_UINT32 comp_index = res_index + layno0 * step_l; + // and finally take each layer of each res of ... + for + (layno = layno0; layno < p_pocs->layno1 ; ++layno) + { + //index = step_r * resno + step_c * compno + step_l * layno; + packet_array[comp_index] = 1; + comp_index += step_l; + } + res_index += step_c; + } + index += step_r; + } + ++p_pocs; + // iterate through all the pocs + for + (i = 1; i < p_nb_pocs ; ++i) + { + OPJ_UINT32 l_last_layno1 = (p_pocs-1)->layno1 ; + layno0 = (p_pocs->layno1 > l_last_layno1)? l_last_layno1 : 0; + index = step_r * p_pocs->resno0; + // take each resolution for each poc + for + (resno = p_pocs->resno0 ; resno < p_pocs->resno1 ; ++resno) + { + OPJ_UINT32 res_index = index + p_pocs->compno0 * step_c; + // take each comp of each resolution for each poc + for + (compno = p_pocs->compno0 ; compno < p_pocs->compno1 ; ++compno) + { + OPJ_UINT32 comp_index = res_index + layno0 * step_l; + // and finally take each layer of each res of ... + for + (layno = layno0; layno < p_pocs->layno1 ; ++layno) + { + //index = step_r * resno + step_c * compno + step_l * layno; + packet_array[comp_index] = 1; + comp_index += step_l; } - fprintf(fd, "\n"); + res_index += step_c; } - fprintf(fd, " }\n"); + index += step_r; } - fprintf(fd, " }\n"); + ++p_pocs; } - fprintf(fd, "}\n"); + + index = 0; + for + (layno = 0; layno < p_num_layers ; ++layno) + { + for + (resno = 0; resno < p_nb_resolutions; ++resno) + { + for + (compno = 0; compno < p_num_comps; ++compno) + { + loss |= (packet_array[index]!=1); + //index = step_r * resno + step_c * compno + step_l * layno; + index += step_c; + } + } + } + if + (loss) + { + opj_event_msg(p_manager , EVT_ERROR, "Missing packets possible loss of data\n"); + } + opj_free(packet_array); + return !loss; } + /* ----------------------------------------------------------------------- */ -static int j2k_get_num_tp(opj_cp_t *cp,int pino,int tileno){ - char *prog; - int i; - int tpnum=1,tpend=0; - opj_tcp_t *tcp = &cp->tcps[tileno]; + +/** + * Gets the number of tile parts used for the given change of progression (if any) and the given tile. + * + * @param cp the coding parameters. + * @param pino the offset of the given poc (i.e. its position in the coding parameter). + * @param tileno the given tile. + * + * @return the number of tile parts. + */ +OPJ_UINT32 j2k_get_num_tp(opj_cp_t *cp,OPJ_UINT32 pino,OPJ_UINT32 tileno) +{ + const OPJ_CHAR *prog = 00; + OPJ_UINT32 i; + OPJ_UINT32 tpnum = 1; + opj_tcp_t *tcp = 00; + opj_poc_t * l_current_poc = 00; + + // preconditions only in debug + assert(tileno < (cp->tw * cp->th)); + assert(pino < (cp->tcps[tileno].numpocs + 1)); + + // get the given tile coding parameter + tcp = &cp->tcps[tileno]; + assert(tcp != 00); + l_current_poc = &(tcp->pocs[pino]); + assert(l_current_poc != 0); + + // get the progression order as a character string prog = j2k_convert_progression_order(tcp->prg); + assert(strlen(prog) > 0); - if(cp->tp_on == 1){ - for(i=0;i<4;i++){ - if(tpend!=1){ - if( cp->tp_flag == prog[i] ){ - tpend=1;cp->tp_pos=i; - } - switch(prog[i]){ + if + (cp->m_specific_param.m_enc.m_tp_on == 1) + { + for + (i=0;i<4;++i) + { + switch + (prog[i]) + { + // component wise case 'C': - tpnum= tpnum * tcp->pocs[pino].compE; + tpnum *= l_current_poc->compE; break; + // resolution wise case 'R': - tpnum= tpnum * tcp->pocs[pino].resE; + tpnum *= l_current_poc->resE; break; + // precinct wise case 'P': - tpnum= tpnum * tcp->pocs[pino].prcE; + tpnum *= l_current_poc->prcE; break; + // layer wise case 'L': - tpnum= tpnum * tcp->pocs[pino].layE; + tpnum *= l_current_poc->layE; break; - } + } + // whould we split here ? + if + ( cp->m_specific_param.m_enc.m_tp_flag == prog[i] ) + { + cp->m_specific_param.m_enc.m_tp_pos=i; + break; } } - }else{ + } + else + { tpnum=1; } return tpnum; } -/** mem allocation for TLM marker*/ -int j2k_calculate_tp(opj_cp_t *cp,int img_numcomp,opj_image_t *image,opj_j2k_t *j2k ){ - int pino,tileno,totnum_tp=0; - j2k->cur_totnum_tp = (int *) opj_malloc(cp->tw * cp->th * sizeof(int)); - for (tileno = 0; tileno < cp->tw * cp->th; tileno++) { - int cur_totnum_tp = 0; - opj_tcp_t *tcp = &cp->tcps[tileno]; - for(pino = 0; pino <= tcp->numpocs; pino++) { - int tp_num=0; - opj_pi_iterator_t *pi = pi_initialise_encode(image, cp, tileno,FINAL_PASS); - if(!pi) { return -1;} - tp_num = j2k_get_num_tp(cp,pino,tileno); - totnum_tp = totnum_tp + tp_num; - cur_totnum_tp = cur_totnum_tp + tp_num; - pi_destroy(pi, cp, tileno); +/** + * Calculates the total number of tile parts needed by the encoder to + * encode such an image. If not enough memory is available, then the function return false. + * + * @param p_nb_tiles pointer that will hold the number of tile parts. + * @param cp the coding parameters for the image. + * @param image the image to encode. + * @param p_j2k the p_j2k encoder. + * @param p_manager the user event manager. + * + * @return true if the function was successful, false else. + */ +bool j2k_calculate_tp( + opj_j2k_t *p_j2k, + opj_cp_t *cp, + OPJ_UINT32 * p_nb_tiles, + opj_image_t *image, + opj_event_mgr_t * p_manager) +{ + OPJ_UINT32 pino,tileno; + OPJ_UINT32 l_nb_tiles; + opj_tcp_t *tcp; + + // preconditions + assert(p_nb_tiles != 00); + assert(cp != 00); + assert(image != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + l_nb_tiles = cp->tw * cp->th; + * p_nb_tiles = 0; + tcp = cp->tcps; + + /* INDEX >> */ + if + (p_j2k->cstr_info) + { + opj_tile_info_t * l_info_tile_ptr = p_j2k->cstr_info->tile; + for + (tileno = 0; tileno < l_nb_tiles; ++tileno) + { + OPJ_UINT32 cur_totnum_tp = 0; + pi_update_encoding_parameters(image,cp,tileno); + for + (pino = 0; pino <= tcp->numpocs; ++pino) + { + OPJ_UINT32 tp_num = j2k_get_num_tp(cp,pino,tileno); + *p_nb_tiles = *p_nb_tiles + tp_num; + cur_totnum_tp += tp_num; + } + tcp->m_nb_tile_parts = cur_totnum_tp; + l_info_tile_ptr->tp = (opj_tp_info_t *) opj_malloc(cur_totnum_tp * sizeof(opj_tp_info_t)); + if + (l_info_tile_ptr->tp == 00) + { + return false; + } + memset(l_info_tile_ptr->tp,0,cur_totnum_tp * sizeof(opj_tp_info_t)); + l_info_tile_ptr->num_tps = cur_totnum_tp; + ++l_info_tile_ptr; + ++tcp; } - j2k->cur_totnum_tp[tileno] = cur_totnum_tp; - /* INDEX >> */ - if (j2k->cstr_info) { - j2k->cstr_info->tile[tileno].num_tps = cur_totnum_tp; - j2k->cstr_info->tile[tileno].tp = (opj_tp_info_t *) opj_malloc(cur_totnum_tp * sizeof(opj_tp_info_t)); + } + else + { + for + (tileno = 0; tileno < l_nb_tiles; ++tileno) + { + OPJ_UINT32 cur_totnum_tp = 0; + pi_update_encoding_parameters(image,cp,tileno); + for + (pino = 0; pino <= tcp->numpocs; ++pino) + { + OPJ_UINT32 tp_num=0; + tp_num = j2k_get_num_tp(cp,pino,tileno); + *p_nb_tiles = *p_nb_tiles + tp_num; + cur_totnum_tp += tp_num; + } + tcp->m_nb_tile_parts = cur_totnum_tp; + ++tcp; } - /* << INDEX */ } - return totnum_tp; + return true; } -static void j2k_write_soc(opj_j2k_t *j2k) { - opj_cio_t *cio = j2k->cio; - cio_write(cio, J2K_MS_SOC, 2); +/** + * Writes the SOC marker (Start Of Codestream) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_soc( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + /* 2 bytes will be written */ + OPJ_BYTE * l_start_stream = 00; + + // preconditions + assert(p_stream != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + l_start_stream = p_j2k->m_specific_param.m_encoder.m_header_tile_data; + + /* write SOC identifier */ + opj_write_bytes(l_start_stream,J2K_MS_SOC,2); + if + (opj_stream_write_data(p_stream,l_start_stream,2,p_manager) != 2) + { + return false; + } /* UniPG>> */ #ifdef USE_JPWL - /* update markers struct */ - j2k_add_marker(j2k->cstr_info, J2K_MS_SOC, cio_tell(cio) - 2, 2); - + j2k_add_marker(p_j2k->cstr_info, J2K_MS_SOC, p_stream_tell(p_stream) - 2, 2); #endif /* USE_JPWL */ + return true; /* <<UniPG */ } -static void j2k_read_soc(opj_j2k_t *j2k) { - j2k->state = J2K_STATE_MHSIZ; +/** + * 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. +*/ +bool j2k_read_soc( + opj_j2k_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 false; + } + opj_read_bytes(l_data,&l_marker,2); + if + (l_marker != J2K_MS_SOC) + { + return false; + } + /* assure length of data is correct (0) */ + p_j2k->m_specific_param.m_decoder.m_state = J2K_DEC_STATE_MHSIZ; /* Index */ - if (j2k->cstr_info) { - j2k->cstr_info->main_head_start = cio_tell(j2k->cio) - 2; - j2k->cstr_info->codestream_size = cio_numbytesleft(j2k->cio) + 2 - j2k->cstr_info->main_head_start; - } -} - -static void j2k_write_siz(opj_j2k_t *j2k) { - int i; - int lenp, len; - - opj_cio_t *cio = j2k->cio; - opj_image_t *image = j2k->image; - opj_cp_t *cp = j2k->cp; - - cio_write(cio, J2K_MS_SIZ, 2); /* SIZ */ - lenp = cio_tell(cio); - cio_skip(cio, 2); - cio_write(cio, cp->rsiz, 2); /* Rsiz (capabilities) */ - cio_write(cio, image->x1, 4); /* Xsiz */ - cio_write(cio, image->y1, 4); /* Ysiz */ - cio_write(cio, image->x0, 4); /* X0siz */ - cio_write(cio, image->y0, 4); /* Y0siz */ - cio_write(cio, cp->tdx, 4); /* XTsiz */ - cio_write(cio, cp->tdy, 4); /* YTsiz */ - cio_write(cio, cp->tx0, 4); /* XT0siz */ - cio_write(cio, cp->ty0, 4); /* YT0siz */ - cio_write(cio, image->numcomps, 2); /* Csiz */ - for (i = 0; i < image->numcomps; i++) { - cio_write(cio, image->comps[i].prec - 1 + (image->comps[i].sgnd << 7), 1); /* Ssiz_i */ - cio_write(cio, image->comps[i].dx, 1); /* XRsiz_i */ - cio_write(cio, image->comps[i].dy, 1); /* YRsiz_i */ - } - len = cio_tell(cio) - lenp; - cio_seek(cio, lenp); - cio_write(cio, len, 2); /* Lsiz */ - cio_seek(cio, lenp + len); -} - -static void j2k_read_siz(opj_j2k_t *j2k) { - int len, i; - - opj_cio_t *cio = j2k->cio; - opj_image_t *image = j2k->image; - opj_cp_t *cp = j2k->cp; - - len = cio_read(cio, 2); /* Lsiz */ - cio_read(cio, 2); /* Rsiz (capabilities) */ - image->x1 = cio_read(cio, 4); /* Xsiz */ - image->y1 = cio_read(cio, 4); /* Ysiz */ - image->x0 = cio_read(cio, 4); /* X0siz */ - image->y0 = cio_read(cio, 4); /* Y0siz */ - cp->tdx = cio_read(cio, 4); /* XTsiz */ - cp->tdy = cio_read(cio, 4); /* YTsiz */ - cp->tx0 = cio_read(cio, 4); /* XT0siz */ - cp->ty0 = cio_read(cio, 4); /* YT0siz */ - - if ((image->x0<0)||(image->x1<0)||(image->y0<0)||(image->y1<0)) { - opj_event_msg(j2k->cinfo, EVT_ERROR, - "%s: invalid image size (x0:%d, x1:%d, y0:%d, y1:%d)\n", - image->x0,image->x1,image->y0,image->y1); - return; + 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 true; +} + +/** + * Writes the SIZ marker (image and tile size) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_siz( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 i; + OPJ_UINT32 l_size_len; + OPJ_BYTE * l_current_ptr; + opj_image_t * l_image = 00; + opj_cp_t *cp = 00; + opj_image_comp_t * l_img_comp = 00; + + // preconditions + assert(p_stream != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + l_image = p_j2k->m_image; + cp = &(p_j2k->m_cp); + l_size_len = 40 + 3 * l_image->numcomps; + l_img_comp = l_image->comps; + + if + (l_size_len > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) + { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_size_len); + if + (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) + { + return false; + } + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_size_len; } - image->numcomps = cio_read(cio, 2); /* Csiz */ + l_current_ptr = p_j2k->m_specific_param.m_encoder.m_header_tile_data; + + /* write SOC identifier */ + opj_write_bytes(l_current_ptr,J2K_MS_SIZ,2); /* SIZ */ + l_current_ptr+=2; + opj_write_bytes(l_current_ptr,l_size_len-2,2); /* L_SIZ */ + l_current_ptr+=2; + opj_write_bytes(l_current_ptr, cp->rsiz, 2); /* Rsiz (capabilities) */ + l_current_ptr+=2; + opj_write_bytes(l_current_ptr, l_image->x1, 4); /* Xsiz */ + l_current_ptr+=4; + opj_write_bytes(l_current_ptr, l_image->y1, 4); /* Ysiz */ + l_current_ptr+=4; + opj_write_bytes(l_current_ptr, l_image->x0, 4); /* X0siz */ + l_current_ptr+=4; + opj_write_bytes(l_current_ptr, l_image->y0, 4); /* Y0siz */ + l_current_ptr+=4; + opj_write_bytes(l_current_ptr, cp->tdx, 4); /* XTsiz */ + l_current_ptr+=4; + opj_write_bytes(l_current_ptr, cp->tdy, 4); /* YTsiz */ + l_current_ptr+=4; + opj_write_bytes(l_current_ptr, cp->tx0, 4); /* XT0siz */ + l_current_ptr+=4; + opj_write_bytes(l_current_ptr, cp->ty0, 4); /* YT0siz */ + l_current_ptr+=4; + opj_write_bytes(l_current_ptr, l_image->numcomps, 2); /* Csiz */ + l_current_ptr+=2; + for + (i = 0; i < l_image->numcomps; ++i) + { + // TODO here with MCT ? + opj_write_bytes(l_current_ptr, l_img_comp->prec - 1 + (l_img_comp->sgnd << 7), 1); /* Ssiz_i */ + ++l_current_ptr; + opj_write_bytes(l_current_ptr, l_img_comp->dx, 1); /* XRsiz_i */ + ++l_current_ptr; + opj_write_bytes(l_current_ptr, l_img_comp->dy, 1); /* YRsiz_i */ + ++l_current_ptr; + ++l_img_comp; + } + if + (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_size_len,p_manager) != l_size_len) + { + return false; + } + return true; +} + +/** + * 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. +*/ +bool j2k_read_siz ( + opj_j2k_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_t *l_cp = 00; + opj_image_comp_t * l_img_comp = 00; + opj_tcp_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); + if + (p_header_size < 36) + { + opj_event_msg(p_manager, EVT_ERROR, "Error with SIZ marker size\n"); + return 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(p_manager, EVT_ERROR, "Error with SIZ marker size\n"); + return 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, (&l_cp->tdx),4); /* XTsiz */ + p_header_data+=4; + opj_read_bytes(p_header_data,&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,(&l_image->numcomps),2); /* Csiz */ + p_header_data+=2; + if + (l_image->numcomps != l_nb_comp) + { + opj_event_msg(p_manager, EVT_ERROR, "Error with SIZ marker size\n"); + return false; + } #ifdef USE_JPWL - if (j2k->cp->correct) { + 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(j2k->cinfo, EVT_ERROR, + 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(j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + opj_event_msg(p_j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); return; } } if (image->numcomps != ((len - 38) / 3)) { - opj_event_msg(j2k->cinfo, JPWL_ASSUME ? EVT_WARNING : EVT_ERROR, + 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(j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + opj_event_msg(p_j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); return; } /* we try to correct */ - opj_event_msg(j2k->cinfo, EVT_WARNING, "- trying to adjust this\n"); + 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(j2k->cinfo, EVT_WARNING, "- setting Lsiz to %d => HYPOTHESIS!!!\n", + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- setting Lsiz to %d => HYPOTHESIS!!!\n", len); } else { image->numcomps = ((len - 38) / 3); - opj_event_msg(j2k->cinfo, EVT_WARNING, "- setting Csiz to %d => HYPOTHESIS!!!\n", + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- setting Csiz to %d => HYPOTHESIS!!!\n", image->numcomps); } } @@ -514,498 +2143,1579 @@ static void j2k_read_siz(opj_j2k_t *j2k) { cp->exp_comps = image->numcomps; } #endif /* USE_JPWL */ - - image->comps = (opj_image_comp_t*) opj_calloc(image->numcomps, sizeof(opj_image_comp_t)); - for (i = 0; i < image->numcomps; i++) { - int tmp, w, h; - tmp = cio_read(cio, 1); /* Ssiz_i */ - image->comps[i].prec = (tmp & 0x7f) + 1; - image->comps[i].sgnd = tmp >> 7; - image->comps[i].dx = cio_read(cio, 1); /* XRsiz_i */ - image->comps[i].dy = cio_read(cio, 1); /* YRsiz_i */ - + + 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(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n"); + return false; + } + memset(l_image->comps,0,l_image->numcomps * sizeof(opj_image_comp_t)); + l_img_comp = l_image->comps; + 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,&l_img_comp->dx,1); /* XRsiz_i */ + ++p_header_data; + opj_read_bytes(p_header_data,&l_img_comp->dy,1); /* YRsiz_i */ + ++p_header_data; #ifdef USE_JPWL - if (j2k->cp->correct) { + 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(j2k->cinfo, JPWL_ASSUME ? EVT_WARNING : EVT_ERROR, + 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(j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + opj_event_msg(p_j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); return; } /* we try to correct */ - opj_event_msg(j2k->cinfo, EVT_WARNING, "- trying to adjust them\n"); + 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(j2k->cinfo, EVT_WARNING, "- setting XRsiz_%d to %d => HYPOTHESIS!!!\n", + 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(j2k->cinfo, EVT_WARNING, "- setting YRsiz_%d to %d => HYPOTHESIS!!!\n", + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- setting YRsiz_%d to %d => HYPOTHESIS!!!\n", i, image->comps[i].dy); } } } #endif /* USE_JPWL */ - - /* TODO: unused ? */ - w = int_ceildiv(image->x1 - image->x0, image->comps[i].dx); - h = int_ceildiv(image->y1 - image->y0, image->comps[i].dy); - - image->comps[i].resno_decoded = 0; /* number of resolution decoded */ - image->comps[i].factor = cp->reduce; /* reducing factor per component */ + 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; } - cp->tw = int_ceildiv(image->x1 - cp->tx0, cp->tdx); - cp->th = int_ceildiv(image->y1 - cp->ty0, cp->tdy); + 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; + 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 (j2k->cp->correct) { + 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(j2k->cinfo, JPWL_ASSUME ? EVT_WARNING : EVT_ERROR, + 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(j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + opj_event_msg(p_j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); return; } /* we try to correct */ - opj_event_msg(j2k->cinfo, EVT_WARNING, "- trying to adjust them\n"); + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- trying to adjust them\n"); if (cp->tw < 1) { cp->tw= 1; - opj_event_msg(j2k->cinfo, EVT_WARNING, "- setting %d tiles in x => HYPOTHESIS!!!\n", + 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(j2k->cinfo, EVT_WARNING, "- too large x, increase expectance of %d\n" + 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(j2k->cinfo, EVT_WARNING, "- setting %d tiles in y => HYPOTHESIS!!!\n", + 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(j2k->cinfo, EVT_WARNING, "- too large y, increase expectance of %d to continue\n", + 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 */ - - cp->tcps = (opj_tcp_t*) opj_calloc(cp->tw * cp->th, sizeof(opj_tcp_t)); - cp->tileno = (int*) opj_malloc(cp->tw * cp->th * sizeof(int)); - cp->tileno_size = 0; + /* memory allocations */ + l_cp->tcps = (opj_tcp_t*) opj_calloc(l_nb_tiles, sizeof(opj_tcp_t)); + if + (l_cp->tcps == 00) + { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n"); + return false; + } + memset(l_cp->tcps,0,l_nb_tiles*sizeof(opj_tcp_t)); #ifdef USE_JPWL - if (j2k->cp->correct) { + if (p_j2k->m_cp->correct) { if (!cp->tcps) { - opj_event_msg(j2k->cinfo, JPWL_ASSUME ? EVT_WARNING : EVT_ERROR, + 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(j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + opj_event_msg(p_j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); return; } } } #endif /* USE_JPWL */ - for (i = 0; i < cp->tw * cp->th; i++) { - cp->tcps[i].POC = 0; - cp->tcps[i].numpocs = 0; - cp->tcps[i].first = 1; + 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(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n"); + return false; } + memset(p_j2k->m_specific_param.m_decoder.m_default_tcp->tccps ,0,l_image->numcomps*sizeof(opj_tccp_t)); - /* Initialization for PPM marker */ - cp->ppm = 0; - cp->ppm_data = NULL; - cp->ppm_data_first = NULL; - cp->ppm_previous = 0; - cp->ppm_store = 0; + p_j2k->m_specific_param.m_decoder.m_default_tcp->m_mct_records = 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(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n"); + return 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_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(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n"); + return 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;i<l_image->numcomps;++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(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n"); + return false; + } + memset(l_current_tile_param->tccps,0,l_image->numcomps * sizeof(opj_tccp_t)); + + ++l_current_tile_param; - j2k->default_tcp->tccps = (opj_tccp_t*) opj_calloc(image->numcomps, sizeof(opj_tccp_t)); - for (i = 0; i < cp->tw * cp->th; i++) { - cp->tcps[i].tccps = (opj_tccp_t*) opj_malloc(image->numcomps * sizeof(opj_tccp_t)); } - j2k->tile_data = (unsigned char**) opj_calloc(cp->tw * cp->th, sizeof(unsigned char*)); - j2k->tile_len = (int*) opj_calloc(cp->tw * cp->th, sizeof(int)); - j2k->state = J2K_STATE_MH; + p_j2k->m_specific_param.m_decoder.m_state = J2K_DEC_STATE_MH; + opj_image_comp_update(l_image,l_cp); /* Index */ - if (j2k->cstr_info) { - opj_codestream_info_t *cstr_info = j2k->cstr_info; - cstr_info->image_w = image->x1 - image->x0; - cstr_info->image_h = image->y1 - image->y0; - cstr_info->numcomps = image->numcomps; - cstr_info->tw = cp->tw; - cstr_info->th = cp->th; - cstr_info->tile_x = cp->tdx; - cstr_info->tile_y = cp->tdy; - cstr_info->tile_Ox = cp->tx0; - cstr_info->tile_Oy = cp->ty0; - cstr_info->tile = (opj_tile_info_t*) opj_calloc(cp->tw * cp->th, sizeof(opj_tile_info_t)); + 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(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n"); + return false; + } + memset(cstr_info->tile,0,l_nb_tiles * sizeof(opj_tile_info_t)); } + return true; } -static void j2k_write_com(opj_j2k_t *j2k) { - unsigned int i; - int lenp, len; - - if(j2k->cp->comment) { - opj_cio_t *cio = j2k->cio; - char *comment = j2k->cp->comment; - - cio_write(cio, J2K_MS_COM, 2); - lenp = cio_tell(cio); - cio_skip(cio, 2); - cio_write(cio, 1, 2); /* General use (IS 8859-15:1999 (Latin) values) */ - for (i = 0; i < strlen(comment); i++) { - cio_write(cio, comment[i], 1); +/** + * Writes the COM marker (comment) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_com( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 l_comment_size; + OPJ_UINT32 l_total_com_size; + const OPJ_CHAR *l_comment; + OPJ_BYTE * l_current_ptr = 00; + + // preconditions + assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); + + l_comment = p_j2k->m_cp.comment; + l_comment_size = strlen(l_comment); + l_total_com_size = l_comment_size + 6; + + if + (l_total_com_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) + { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_total_com_size); + if + (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) + { + return false; } - len = cio_tell(cio) - lenp; - cio_seek(cio, lenp); - cio_write(cio, len, 2); - cio_seek(cio, lenp + len); + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_total_com_size; + } + l_current_ptr = p_j2k->m_specific_param.m_encoder.m_header_tile_data; + opj_write_bytes(l_current_ptr,J2K_MS_COM , 2); /* COM */ + l_current_ptr+=2; + opj_write_bytes(l_current_ptr,l_total_com_size - 2 , 2); /* L_COM */ + l_current_ptr+=2; + opj_write_bytes(l_current_ptr,1 , 2); /* General use (IS 8859-15:1999 (Latin) values) */ + l_current_ptr+=2, + memcpy( l_current_ptr,l_comment,l_comment_size); + if + (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_total_com_size,p_manager) != l_total_com_size) + { + return false; } + return true; } -static void j2k_read_com(opj_j2k_t *j2k) { - int len; - - opj_cio_t *cio = j2k->cio; +/** + * 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. +*/ +bool j2k_read_com ( + opj_j2k_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 true; +} - len = cio_read(cio, 2); - cio_skip(cio, len - 2); +/** + * Gets the size taken by writting a SPCod or SPCoc for the given tile and component. + * + * @param p_tile_no the tile indix. + * @param p_comp_no the component being outputted. + * @param p_j2k the J2K codec. + * + * @return the number of bytes taken by the SPCod element. + */ +OPJ_UINT32 j2k_get_SPCod_SPCoc_size ( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no + ) +{ + opj_cp_t *l_cp = 00; + opj_tcp_t *l_tcp = 00; + opj_tccp_t *l_tccp = 00; + + // preconditions + assert(p_j2k != 00); + + l_cp = &(p_j2k->m_cp); + l_tcp = &l_cp->tcps[p_tile_no]; + l_tccp = &l_tcp->tccps[p_comp_no]; + + // preconditions again + assert(p_tile_no < (l_cp->tw * l_cp->th)); + assert(p_comp_no < p_j2k->m_image->numcomps); + + if + (l_tccp->csty & J2K_CCP_CSTY_PRT) + { + return 5 + l_tccp->numresolutions; + } + else + { + return 5; + } } -static void j2k_write_cox(opj_j2k_t *j2k, int compno) { - int i; - opj_cp_t *cp = j2k->cp; - opj_tcp_t *tcp = &cp->tcps[j2k->curtileno]; - opj_tccp_t *tccp = &tcp->tccps[compno]; - opj_cio_t *cio = j2k->cio; +/** + * Writes a SPCod or SPCoc element, i.e. the coding style of a given component of a tile. + * + * @param p_comp_no the component number to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. + * +*/ +bool j2k_write_SPCod_SPCoc( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_header_size, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 i; + opj_cp_t *l_cp = 00; + opj_tcp_t *l_tcp = 00; + opj_tccp_t *l_tccp = 00; + + // preconditions + assert(p_j2k != 00); + assert(p_header_size != 00); + assert(p_manager != 00); + assert(p_data != 00); + + l_cp = &(p_j2k->m_cp); + l_tcp = &l_cp->tcps[p_tile_no]; + l_tccp = &l_tcp->tccps[p_comp_no]; - cio_write(cio, tccp->numresolutions - 1, 1); /* SPcox (D) */ - cio_write(cio, tccp->cblkw - 2, 1); /* SPcox (E) */ - cio_write(cio, tccp->cblkh - 2, 1); /* SPcox (F) */ - cio_write(cio, tccp->cblksty, 1); /* SPcox (G) */ - cio_write(cio, tccp->qmfbid, 1); /* SPcox (H) */ + // preconditions again + assert(p_tile_no < (l_cp->tw * l_cp->th)); + assert(p_comp_no <(p_j2k->m_image->numcomps)); - if (tccp->csty & J2K_CCP_CSTY_PRT) { - for (i = 0; i < tccp->numresolutions; i++) { - cio_write(cio, tccp->prcw[i] + (tccp->prch[i] << 4), 1); /* SPcox (I_i) */ + if + (*p_header_size < 5) + { + opj_event_msg(p_manager, EVT_ERROR, "Error writting SPCod SPCoc element\n"); + return false; + } + + opj_write_bytes(p_data,l_tccp->numresolutions - 1, 1); /* SPcoc (D) */ + ++p_data; + opj_write_bytes(p_data,l_tccp->cblkw - 2, 1); /* SPcoc (E) */ + ++p_data; + opj_write_bytes(p_data,l_tccp->cblkh - 2, 1); /* SPcoc (F) */ + ++p_data; + opj_write_bytes(p_data,l_tccp->cblksty, 1); /* SPcoc (G) */ + ++p_data; + opj_write_bytes(p_data,l_tccp->qmfbid, 1); /* SPcoc (H) */ + ++p_data; + + *p_header_size = *p_header_size - 5; + if + (l_tccp->csty & J2K_CCP_CSTY_PRT) + { + if + (*p_header_size < l_tccp->numresolutions) + { + opj_event_msg(p_manager, EVT_ERROR, "Error writting SPCod SPCoc element\n"); + return false; + } + for + (i = 0; i < l_tccp->numresolutions; ++i) + { + opj_write_bytes(p_data,l_tccp->prcw[i] + (l_tccp->prch[i] << 4), 1); /* SPcoc (I_i) */ + ++p_data; } + *p_header_size = *p_header_size - l_tccp->numresolutions; + } + return true; } -static void j2k_read_cox(opj_j2k_t *j2k, int compno) { - int i; - opj_cp_t *cp = j2k->cp; - opj_tcp_t *tcp = j2k->state == J2K_STATE_TPH ? &cp->tcps[j2k->curtileno] : j2k->default_tcp; - opj_tccp_t *tccp = &tcp->tccps[compno]; - opj_cio_t *cio = j2k->cio; +/** + * 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. +*/ +bool j2k_read_SPCod_SPCoc( + opj_j2k_t *p_j2k, + OPJ_UINT32 compno, + OPJ_BYTE * p_header_data, + OPJ_UINT32 * p_header_size, + struct opj_event_mgr * p_manager + ) +{ + // loop + OPJ_UINT32 i; + + opj_cp_t *l_cp = 00; + opj_tcp_t *l_tcp = 00; + opj_tccp_t *l_tccp = 00; + OPJ_BYTE * l_current_ptr = 00; + OPJ_UINT32 l_tmp; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_header_data != 00); + - tccp->numresolutions = cio_read(cio, 1) + 1; /* SPcox (D) */ + l_cp = &(p_j2k->m_cp); + l_tcp = p_j2k->m_specific_param.m_decoder.m_state == 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(p_manager, EVT_ERROR, "Error reading SPCod SPCoc element\n"); + return 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 (cp->reduce >= tccp->numresolutions) { - opj_event_msg(j2k->cinfo, EVT_ERROR, "Error decoding component %d.\nThe number of resolutions to remove is higher than the number " + if + (l_cp->m_specific_param.m_dec.m_reduce >= l_tccp->numresolutions) + { + opj_event_msg(p_manager, EVT_ERROR, "Error decoding component %d.\nThe number of resolutions to remove is higher than the number " "of resolutions of this component\nModify the cp_reduce parameter.\n\n", compno); - j2k->state |= J2K_STATE_ERR; + p_j2k->m_specific_param.m_decoder.m_state |= J2K_DEC_STATE_ERR; + return false; } + + opj_read_bytes(l_current_ptr,&l_tccp->cblkw ,1); /* SPcoc (E) */ + ++l_current_ptr; + l_tccp->cblkw += 2; - tccp->cblkw = cio_read(cio, 1) + 2; /* SPcox (E) */ - tccp->cblkh = cio_read(cio, 1) + 2; /* SPcox (F) */ - tccp->cblksty = cio_read(cio, 1); /* SPcox (G) */ - tccp->qmfbid = cio_read(cio, 1); /* SPcox (H) */ - if (tccp->csty & J2K_CP_CSTY_PRT) { - for (i = 0; i < tccp->numresolutions; i++) { - int tmp = cio_read(cio, 1); /* SPcox (I_i) */ - tccp->prcw[i] = tmp & 0xf; - tccp->prch[i] = tmp >> 4; + 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(p_manager, EVT_ERROR, "Error reading SPCod SPCoc element\n"); + return 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(j2k->cstr_info && compno == 0) { - for (i = 0; i < tccp->numresolutions; i++) { - if (tccp->csty & J2K_CP_CSTY_PRT) { - j2k->cstr_info->tile[j2k->curtileno].pdx[i] = tccp->prcw[i]; - j2k->cstr_info->tile[j2k->curtileno].pdy[i] = tccp->prch[i]; - } - else { - j2k->cstr_info->tile[j2k->curtileno].pdx[i] = 15; - j2k->cstr_info->tile[j2k->curtileno].pdx[i] = 15; - } - } + 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 true; } -static void j2k_write_cod(opj_j2k_t *j2k) { - opj_cp_t *cp = NULL; - opj_tcp_t *tcp = NULL; - int lenp, len; +/** + * 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_t *p_j2k + ) +{ + // loop + OPJ_UINT32 i; + + opj_cp_t *l_cp = 00; + opj_tcp_t *l_tcp = 00; + opj_tccp_t *l_ref_tccp = 00; + opj_tccp_t *l_copied_tccp = 00; + 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_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;i<p_j2k->m_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; + } +} + + - opj_cio_t *cio = j2k->cio; +/** + * Writes the COD marker (Coding style default) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_cod( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + opj_cp_t *l_cp = 00; + opj_tcp_t *l_tcp = 00; + OPJ_UINT32 l_code_size,l_remaining_size; + OPJ_BYTE * l_current_data = 00; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_cp = &(p_j2k->m_cp); + l_tcp = &l_cp->tcps[p_j2k->m_current_tile_number]; + l_code_size = 9 + j2k_get_SPCod_SPCoc_size(p_j2k,p_j2k->m_current_tile_number,0); + l_remaining_size = l_code_size; - cio_write(cio, J2K_MS_COD, 2); /* COD */ + if + (l_code_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) + { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_code_size); + if + (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) + { + return false; + } + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_code_size; + } + + l_current_data = p_j2k->m_specific_param.m_encoder.m_header_tile_data; + + opj_write_bytes(l_current_data,J2K_MS_COD,2); /* COD */ + l_current_data += 2; - lenp = cio_tell(cio); - cio_skip(cio, 2); + opj_write_bytes(l_current_data,l_code_size-2,2); /* L_COD */ + l_current_data += 2; + + opj_write_bytes(l_current_data,l_tcp->csty,1); /* Scod */ + ++l_current_data; + + opj_write_bytes(l_current_data,l_tcp->prg,1); /* SGcod (A) */ + ++l_current_data; - cp = j2k->cp; - tcp = &cp->tcps[j2k->curtileno]; + opj_write_bytes(l_current_data,l_tcp->numlayers,2); /* SGcod (B) */ + l_current_data+=2; - cio_write(cio, tcp->csty, 1); /* Scod */ - cio_write(cio, tcp->prg, 1); /* SGcod (A) */ - cio_write(cio, tcp->numlayers, 2); /* SGcod (B) */ - cio_write(cio, tcp->mct, 1); /* SGcod (C) */ + opj_write_bytes(l_current_data,l_tcp->mct,1); /* SGcod (C) */ + ++l_current_data; + + l_remaining_size -= 9; - j2k_write_cox(j2k, 0); - len = cio_tell(cio) - lenp; - cio_seek(cio, lenp); - cio_write(cio, len, 2); /* Lcod */ - cio_seek(cio, lenp + len); + if + (! j2k_write_SPCod_SPCoc(p_j2k,p_j2k->m_current_tile_number,0,l_current_data,&l_remaining_size,p_manager)) + { + opj_event_msg(p_manager, EVT_ERROR, "Error writting COD marker\n"); + return false; + } + if + (l_remaining_size != 0) + { + opj_event_msg(p_manager, EVT_ERROR, "Error writting COD marker\n"); + return false; + } + + if + (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_code_size,p_manager) != l_code_size) + { + return false; + } + return true; } -static void j2k_read_cod(opj_j2k_t *j2k) { - int len, i, pos; +/** + * 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. +*/ +bool j2k_read_cod ( + opj_j2k_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_t *l_cp = 00; + opj_tcp_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_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; - opj_cio_t *cio = j2k->cio; - opj_cp_t *cp = j2k->cp; - opj_tcp_t *tcp = j2k->state == J2K_STATE_TPH ? &cp->tcps[j2k->curtileno] : j2k->default_tcp; - opj_image_t *image = j2k->image; + // make sure room is sufficient + if + (p_header_size < 5) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading COD marker\n"); + return false; + } - len = cio_read(cio, 2); /* Lcod */ - tcp->csty = cio_read(cio, 1); /* Scod */ - tcp->prg = (OPJ_PROG_ORDER)cio_read(cio, 1); /* SGcod (A) */ - tcp->numlayers = cio_read(cio, 2); /* SGcod (B) */ - tcp->mct = cio_read(cio, 1); /* SGcod (C) */ + 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; - pos = cio_tell(cio); - for (i = 0; i < image->numcomps; i++) { - tcp->tccps[i].csty = tcp->csty & J2K_CP_CSTY_PRT; - cio_seek(cio, pos); - j2k_read_cox(j2k, i); + 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(p_manager, EVT_ERROR, "Error reading COD marker\n"); + return false; + } + if + (p_header_size != 0) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading COD marker\n"); + return false; + } + j2k_copy_tile_component_parameters(p_j2k); + + /* Index */ - if (j2k->cstr_info) { - opj_codestream_info_t *cstr_info = j2k->cstr_info; - cstr_info->prog = tcp->prg; - cstr_info->numlayers = tcp->numlayers; - cstr_info->numdecompos = (int*) opj_malloc(image->numcomps * sizeof(int)); - for (i = 0; i < image->numcomps; i++) { - cstr_info->numdecompos[i] = tcp->tccps[i].numresolutions - 1; + 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 true; +} + +/** + * Writes the COC marker (Coding style component) + * + * @param p_comp_no the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_coc( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_comp_no, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 l_coc_size,l_remaining_size; + OPJ_UINT32 l_comp_room; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_comp_room = (p_j2k->m_image->numcomps <= 256) ? 1 : 2; + + l_coc_size = 5 + l_comp_room + j2k_get_SPCod_SPCoc_size(p_j2k,p_j2k->m_current_tile_number,p_comp_no); + if + (l_coc_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) + { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_coc_size); + if + (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) + { + return false; + } + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_coc_size; + } + + j2k_write_coc_in_memory(p_j2k,p_comp_no,p_j2k->m_specific_param.m_encoder.m_header_tile_data,&l_remaining_size,p_manager); + + if + (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_coc_size,p_manager) != l_coc_size) + { + return false; + } + return true; +} + +/** + * Gets the maximum size taken by a coc. + * + * @param p_j2k the jpeg2000 codec to use. + */ +OPJ_UINT32 j2k_get_max_coc_size(opj_j2k_t *p_j2k) +{ + OPJ_UINT32 i,j; + OPJ_UINT32 l_nb_comp; + OPJ_UINT32 l_nb_tiles; + OPJ_UINT32 l_max = 0; + + // preconditions + + l_nb_tiles = p_j2k->m_cp.tw * p_j2k->m_cp.th ; + l_nb_comp = p_j2k->m_image->numcomps; + + for + (i=0;i<l_nb_tiles;++i) + { + for + (j=0;j<l_nb_comp;++j) + { + l_max = uint_max(l_max,j2k_get_SPCod_SPCoc_size(p_j2k,i,j)); + } + } + return 6 + l_max; +} + +/** + * Gets the maximum size taken by the toc headers of all the tile parts of any given tile. + */ +OPJ_UINT32 j2k_get_max_toc_size (opj_j2k_t *p_j2k) +{ + OPJ_UINT32 i; + OPJ_UINT32 l_nb_tiles; + OPJ_UINT32 l_max = 0; + opj_tcp_t * l_tcp = 00; + // preconditions + + l_tcp = p_j2k->m_cp.tcps; + l_nb_tiles = p_j2k->m_cp.tw * p_j2k->m_cp.th ; + + for + (i=0;i<l_nb_tiles;++i) + { + l_max = uint_max(l_max,l_tcp->m_nb_tile_parts); + ++l_tcp; + } + return 12 * l_max; } -static void j2k_write_coc(opj_j2k_t *j2k, int compno) { - int lenp, len; - opj_cp_t *cp = j2k->cp; - opj_tcp_t *tcp = &cp->tcps[j2k->curtileno]; - opj_image_t *image = j2k->image; - opj_cio_t *cio = j2k->cio; +/** + * Gets the maximum size taken by the headers of the SOT. + * + * @param p_j2k the jpeg2000 codec to use. + */ +OPJ_UINT32 j2k_get_specific_header_sizes(opj_j2k_t *p_j2k) +{ + OPJ_UINT32 l_nb_bytes = 0; + OPJ_UINT32 l_nb_comps; + OPJ_UINT32 l_coc_bytes,l_qcc_bytes; + + + l_nb_comps = p_j2k->m_image->numcomps - 1; + l_nb_bytes += j2k_get_max_toc_size(p_j2k); + if + (p_j2k->m_cp.m_specific_param.m_enc.m_cinema == 0) + { + l_coc_bytes = j2k_get_max_coc_size(p_j2k); + l_nb_bytes += l_nb_comps * l_coc_bytes; + l_qcc_bytes = j2k_get_max_qcc_size(p_j2k); + l_nb_bytes += l_nb_comps * l_qcc_bytes; + } + l_nb_bytes += j2k_get_max_poc_size(p_j2k); + /*** DEVELOPER CORNER, Add room for your headers ***/ - cio_write(cio, J2K_MS_COC, 2); /* COC */ - lenp = cio_tell(cio); - cio_skip(cio, 2); - cio_write(cio, compno, image->numcomps <= 256 ? 1 : 2); /* Ccoc */ - cio_write(cio, tcp->tccps[compno].csty, 1); /* Scoc */ - j2k_write_cox(j2k, compno); - len = cio_tell(cio) - lenp; - cio_seek(cio, lenp); - cio_write(cio, len, 2); /* Lcoc */ - cio_seek(cio, lenp + len); + + return l_nb_bytes; } -static void j2k_read_coc(opj_j2k_t *j2k) { - int len, compno; - opj_cp_t *cp = j2k->cp; - opj_tcp_t *tcp = j2k->state == J2K_STATE_TPH ? &cp->tcps[j2k->curtileno] : j2k->default_tcp; - opj_image_t *image = j2k->image; - opj_cio_t *cio = j2k->cio; +/** + * Writes the COC marker (Coding style component) + * + * @param p_comp_no the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +void j2k_write_coc_in_memory( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_comp_no, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + struct opj_event_mgr * p_manager + ) +{ + opj_cp_t *l_cp = 00; + opj_tcp_t *l_tcp = 00; + OPJ_UINT32 l_coc_size,l_remaining_size; + OPJ_BYTE * l_current_data = 00; + opj_image_t *l_image = 00; + OPJ_UINT32 l_comp_room; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + + l_cp = &(p_j2k->m_cp); + l_tcp = &l_cp->tcps[p_j2k->m_current_tile_number]; + l_image = p_j2k->m_image; + l_comp_room = (l_image->numcomps <= 256) ? 1 : 2; + + l_coc_size = 5 + l_comp_room + j2k_get_SPCod_SPCoc_size(p_j2k,p_j2k->m_current_tile_number,p_comp_no); + l_remaining_size = l_coc_size; + + l_current_data = p_data; + + opj_write_bytes(l_current_data,J2K_MS_COC,2); /* COC */ + l_current_data += 2; + opj_write_bytes(l_current_data,l_coc_size-2,2); /* L_COC */ + l_current_data += 2; + opj_write_bytes(l_current_data,p_comp_no, l_comp_room); /* Ccoc */ + l_current_data+=l_comp_room; + opj_write_bytes(l_current_data, l_tcp->tccps[p_comp_no].csty, 1); /* Scoc */ + ++l_current_data; + l_remaining_size -= (5 + l_comp_room); + j2k_write_SPCod_SPCoc(p_j2k,p_j2k->m_current_tile_number,0,l_current_data,&l_remaining_size,p_manager); + * p_data_written = l_coc_size; +} + + +/** + * 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. +*/ +bool j2k_read_coc ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ) +{ + opj_cp_t *l_cp = 00; + opj_tcp_t *l_tcp = 00; + opj_image_t *l_image = 00; + 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_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; - len = cio_read(cio, 2); /* Lcoc */ - compno = cio_read(cio, image->numcomps <= 256 ? 1 : 2); /* Ccoc */ - tcp->tccps[compno].csty = cio_read(cio, 1); /* Scoc */ - j2k_read_cox(j2k, compno); + 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(p_manager, EVT_ERROR, "Error reading COC marker\n"); + return 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(p_manager, EVT_ERROR, "Error reading COC marker (bad number of components)\n"); + return 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(p_manager, EVT_ERROR, "Error reading COC marker\n"); + return false; + } + if + (p_header_size != 0) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading COC marker\n"); + return false; + } + return true; } -static void j2k_write_qcx(opj_j2k_t *j2k, int compno) { - int bandno, numbands; - int expn, mant; +/** + * Gets the size taken by writting SQcd or SQcc element, i.e. the quantization values of a band in the QCD or QCC. + * + * @param p_tile_no the tile indix. + * @param p_comp_no the component being outputted. + * @param p_j2k the J2K codec. + * + * @return the number of bytes taken by the SPCod element. + */ +OPJ_UINT32 j2k_get_SQcd_SQcc_size ( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no + ) +{ + OPJ_UINT32 l_num_bands; + + opj_cp_t *l_cp = 00; + opj_tcp_t *l_tcp = 00; + opj_tccp_t *l_tccp = 00; + + // preconditions + assert(p_j2k != 00); + + l_cp = &(p_j2k->m_cp); + l_tcp = &l_cp->tcps[p_tile_no]; + l_tccp = &l_tcp->tccps[p_comp_no]; - opj_cp_t *cp = j2k->cp; - opj_tcp_t *tcp = &cp->tcps[j2k->curtileno]; - opj_tccp_t *tccp = &tcp->tccps[compno]; - opj_cio_t *cio = j2k->cio; + // preconditions again + assert(p_tile_no < l_cp->tw * l_cp->th); + assert(p_comp_no < p_j2k->m_image->numcomps); - cio_write(cio, tccp->qntsty + (tccp->numgbits << 5), 1); /* Sqcx */ - numbands = tccp->qntsty == J2K_CCP_QNTSTY_SIQNT ? 1 : tccp->numresolutions * 3 - 2; + l_num_bands = (l_tccp->qntsty == J2K_CCP_QNTSTY_SIQNT) ? 1 : (l_tccp->numresolutions * 3 - 2); - for (bandno = 0; bandno < numbands; bandno++) { - expn = tccp->stepsizes[bandno].expn; - mant = tccp->stepsizes[bandno].mant; - - if (tccp->qntsty == J2K_CCP_QNTSTY_NOQNT) { - cio_write(cio, expn << 3, 1); /* SPqcx_i */ - } else { - cio_write(cio, (expn << 11) + mant, 2); /* SPqcx_i */ + if + (l_tccp->qntsty == J2K_CCP_QNTSTY_NOQNT) + { + return 1 + l_num_bands; + } + else + { + return 1 + 2*l_num_bands; + } +} + +/** + * Writes a SQcd or SQcc element, i.e. the quantization values of a band. + * + * @param p_tile_no the tile to output. + * @param p_comp_no the component number to output. + * @param p_data the data buffer. + * @param p_header_size pointer to the size of the data buffer, it is changed by the function. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. + * +*/ +bool j2k_write_SQcd_SQcc( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_header_size, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 l_header_size; + OPJ_UINT32 l_band_no, l_num_bands; + OPJ_UINT32 l_expn,l_mant; + + opj_cp_t *l_cp = 00; + opj_tcp_t *l_tcp = 00; + opj_tccp_t *l_tccp = 00; + + // preconditions + assert(p_j2k != 00); + assert(p_header_size != 00); + assert(p_manager != 00); + assert(p_data != 00); + + l_cp = &(p_j2k->m_cp); + l_tcp = &l_cp->tcps[p_tile_no]; + l_tccp = &l_tcp->tccps[p_comp_no]; + + // preconditions again + assert(p_tile_no < l_cp->tw * l_cp->th); + assert(p_comp_no <p_j2k->m_image->numcomps); + + l_num_bands = (l_tccp->qntsty == J2K_CCP_QNTSTY_SIQNT) ? 1 : (l_tccp->numresolutions * 3 - 2); + + if + (l_tccp->qntsty == J2K_CCP_QNTSTY_NOQNT) + { + l_header_size = 1 + l_num_bands; + if + (*p_header_size < l_header_size) + { + opj_event_msg(p_manager, EVT_ERROR, "Error writting SQcd SQcc element\n"); + return false; + } + opj_write_bytes(p_data,l_tccp->qntsty + (l_tccp->numgbits << 5), 1); /* Sqcx */ + ++p_data; + for + (l_band_no = 0; l_band_no < l_num_bands; ++l_band_no) + { + l_expn = l_tccp->stepsizes[l_band_no].expn; + opj_write_bytes(p_data, l_expn << 3, 1); /* SPqcx_i */ + ++p_data; } } + else + { + l_header_size = 1 + 2*l_num_bands; + if + (*p_header_size < l_header_size) + { + opj_event_msg(p_manager, EVT_ERROR, "Error writting SQcd SQcc element\n"); + return false; + } + opj_write_bytes(p_data,l_tccp->qntsty + (l_tccp->numgbits << 5), 1); /* Sqcx */ + ++p_data; + for + (l_band_no = 0; l_band_no < l_num_bands; ++l_band_no) + { + l_expn = l_tccp->stepsizes[l_band_no].expn; + l_mant = l_tccp->stepsizes[l_band_no].mant; + opj_write_bytes(p_data, (l_expn << 11) + l_mant, 2); /* SPqcx_i */ + p_data += 2; + } + } + *p_header_size = *p_header_size - l_header_size; + return true; } -static void j2k_read_qcx(opj_j2k_t *j2k, int compno, int len) { - int tmp; - int bandno, numbands; +/** + * 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. +*/ +bool j2k_read_SQcd_SQcc( + opj_j2k_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_t *l_cp = 00; + opj_tcp_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_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(p_manager, EVT_ERROR, "Error reading SQcd or SQcc element\n"); + return false; + } + * p_header_size -= 1; - opj_cp_t *cp = j2k->cp; - opj_tcp_t *tcp = j2k->state == J2K_STATE_TPH ? &cp->tcps[j2k->curtileno] : j2k->default_tcp; - opj_tccp_t *tccp = &tcp->tccps[compno]; - opj_cio_t *cio = j2k->cio; + opj_read_bytes(l_current_ptr, &l_tmp ,1); /* Sqcx */ + ++l_current_ptr; - tmp = cio_read(cio, 1); /* Sqcx */ - tccp->qntsty = tmp & 0x1f; - tccp->numgbits = tmp >> 5; - numbands = (tccp->qntsty == J2K_CCP_QNTSTY_SIQNT) ? - 1 : ((tccp->qntsty == J2K_CCP_QNTSTY_NOQNT) ? len - 1 : (len - 1) / 2); + 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; + } #ifdef USE_JPWL - if (j2k->cp->correct) { + 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(j2k->cinfo, JPWL_ASSUME ? EVT_WARNING : EVT_ERROR, + 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(j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + opj_event_msg(p_j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); return; } /* we try to correct */ numbands = 1; - opj_event_msg(j2k->cinfo, EVT_WARNING, "- trying to adjust them\n" + 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 */ - - for (bandno = 0; bandno < numbands; bandno++) { - int expn, mant; - if (tccp->qntsty == J2K_CCP_QNTSTY_NOQNT) { - expn = cio_read(cio, 1) >> 3; /* SPqcx_i */ - mant = 0; - } else { - tmp = cio_read(cio, 2); /* SPqcx_i */ - expn = tmp >> 11; - mant = tmp & 0x7ff; + 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; } - tccp->stepsizes[bandno].expn = expn; - tccp->stepsizes[bandno].mant = mant; + * p_header_size = * p_header_size - 2*l_num_band; } /* Add Antonin : if scalar_derived -> compute other stepsizes */ - if (tccp->qntsty == J2K_CCP_QNTSTY_SIQNT) { - for (bandno = 1; bandno < J2K_MAXBANDS; bandno++) { - tccp->stepsizes[bandno].expn = - ((tccp->stepsizes[0].expn) - ((bandno - 1) / 3) > 0) ? - (tccp->stepsizes[0].expn) - ((bandno - 1) / 3) : 0; - tccp->stepsizes[bandno].mant = tccp->stepsizes[0].mant; + 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; } + } - /* ddA */ + return true; } -static void j2k_write_qcd(opj_j2k_t *j2k) { - int lenp, len; - opj_cio_t *cio = j2k->cio; + +/** + * 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_t *p_j2k + ) +{ + // loop + OPJ_UINT32 i; - cio_write(cio, J2K_MS_QCD, 2); /* QCD */ - lenp = cio_tell(cio); - cio_skip(cio, 2); - j2k_write_qcx(j2k, 0); - len = cio_tell(cio) - lenp; - cio_seek(cio, lenp); - cio_write(cio, len, 2); /* Lqcd */ - cio_seek(cio, lenp + len); + opj_cp_t *l_cp = 00; + opj_tcp_t *l_tcp = 00; + opj_tccp_t *l_ref_tccp = 00; + opj_tccp_t *l_copied_tccp = 00; + 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_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;i<p_j2k->m_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; + } } -static void j2k_read_qcd(opj_j2k_t *j2k) { - int len, i, pos; - opj_cio_t *cio = j2k->cio; - opj_image_t *image = j2k->image; + +/** + * Writes the QCD marker (quantization default) + * + * @param p_comp_number the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_qcd( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + opj_cp_t *l_cp = 00; + opj_tcp_t *l_tcp = 00; + OPJ_UINT32 l_qcd_size,l_remaining_size; + OPJ_BYTE * l_current_data = 00; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_cp = &(p_j2k->m_cp); + l_tcp = &l_cp->tcps[p_j2k->m_current_tile_number]; + l_qcd_size = 4 + j2k_get_SQcd_SQcc_size(p_j2k,p_j2k->m_current_tile_number,0); + l_remaining_size = l_qcd_size; + + if + (l_qcd_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) + { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_qcd_size); + if + (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) + { + return false; + } + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_qcd_size; + } + l_current_data = p_j2k->m_specific_param.m_encoder.m_header_tile_data; + + opj_write_bytes(l_current_data,J2K_MS_QCD,2); /* QCD */ + l_current_data += 2; - len = cio_read(cio, 2); /* Lqcd */ - pos = cio_tell(cio); - for (i = 0; i < image->numcomps; i++) { - cio_seek(cio, pos); - j2k_read_qcx(j2k, i, len - 2); + opj_write_bytes(l_current_data,l_qcd_size-2,2); /* L_QCD */ + l_current_data += 2; + + l_remaining_size -= 4; + + if + (! j2k_write_SQcd_SQcc(p_j2k,p_j2k->m_current_tile_number,0,l_current_data,&l_remaining_size,p_manager)) + { + opj_event_msg(p_manager, EVT_ERROR, "Error writting QCD marker\n"); + return false; + } + if + (l_remaining_size != 0) + { + opj_event_msg(p_manager, EVT_ERROR, "Error writting QCD marker\n"); + return false; } -} -static void j2k_write_qcc(opj_j2k_t *j2k, int compno) { - int lenp, len; + if + (opj_stream_write_data(p_stream, p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_qcd_size,p_manager) != l_qcd_size) + { + return false; + } + return true; +} - opj_cio_t *cio = j2k->cio; +/** + * 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. +*/ +bool j2k_read_qcd ( + opj_j2k_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); - cio_write(cio, J2K_MS_QCC, 2); /* QCC */ - lenp = cio_tell(cio); - cio_skip(cio, 2); - cio_write(cio, compno, j2k->image->numcomps <= 256 ? 1 : 2); /* Cqcc */ - j2k_write_qcx(j2k, compno); - len = cio_tell(cio) - lenp; - cio_seek(cio, lenp); - cio_write(cio, len, 2); /* Lqcc */ - cio_seek(cio, lenp + len); + if + (! j2k_read_SQcd_SQcc(p_j2k,0,p_header_data,&p_header_size,p_manager)) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading QCD marker\n"); + return false; + } + if + (p_header_size != 0) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading QCD marker\n"); + return false; + } + j2k_copy_tile_quantization_parameters(p_j2k); + return true; } -static void j2k_read_qcc(opj_j2k_t *j2k) { - int len, compno; - int numcomp = j2k->image->numcomps; - opj_cio_t *cio = j2k->cio; + +/** + * Writes the QCC marker (quantization component) + * + * @param p_comp_no the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_qcc( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_comp_no, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 l_qcc_size,l_remaining_size; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_qcc_size = 6 + j2k_get_SQcd_SQcc_size(p_j2k,p_j2k->m_current_tile_number,p_comp_no); + l_remaining_size = l_qcc_size; + if + (l_qcc_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) + { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_qcc_size); + if + (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) + { + return false; + } + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_qcc_size; + } + j2k_write_qcc_in_memory(p_j2k,p_comp_no,p_j2k->m_specific_param.m_encoder.m_header_tile_data,&l_remaining_size,p_manager); + + if + (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_qcc_size,p_manager) != l_qcc_size) + { + return false; + } + return true; +} + + +/** + * Writes the QCC marker (quantization component) + * + * @param p_comp_no the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +void j2k_write_qcc_in_memory( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_comp_no, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 l_qcc_size,l_remaining_size; + OPJ_BYTE * l_current_data = 00; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + + l_qcc_size = 6 + j2k_get_SQcd_SQcc_size(p_j2k,p_j2k->m_current_tile_number,p_comp_no); + l_remaining_size = l_qcc_size; + + l_current_data = p_data; + + opj_write_bytes(l_current_data,J2K_MS_QCC,2); /* QCC */ + l_current_data += 2; - len = cio_read(cio, 2); /* Lqcc */ - compno = cio_read(cio, numcomp <= 256 ? 1 : 2); /* Cqcc */ + if + (p_j2k->m_image->numcomps <= 256) + { + --l_qcc_size; + opj_write_bytes(l_current_data,l_qcc_size-2,2); /* L_QCC */ + l_current_data += 2; + opj_write_bytes(l_current_data, p_comp_no, 1); /* Cqcc */ + ++l_current_data; + // in the case only one byte is sufficient the last byte allocated is useless -> still do -6 for available + l_remaining_size -= 6; + } + else + { + opj_write_bytes(l_current_data,l_qcc_size-2,2); /* L_QCC */ + l_current_data += 2; + opj_write_bytes(l_current_data, p_comp_no, 2); /* Cqcc */ + l_current_data+=2; + l_remaining_size -= 6; + } + j2k_write_SQcd_SQcc(p_j2k,p_j2k->m_current_tile_number,p_comp_no,l_current_data,&l_remaining_size,p_manager); + * p_data_written = l_qcc_size; +} + +/** + * Gets the maximum size taken by a qcc. + */ +OPJ_UINT32 j2k_get_max_qcc_size (opj_j2k_t *p_j2k) +{ + return j2k_get_max_coc_size(p_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. +*/ +bool j2k_read_qcc( + opj_j2k_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 (j2k->cp->correct) { + if (p_j2k->m_cp->correct) { - static int backup_compno = 0; + static OPJ_UINT32 backup_compno = 0; /* compno is negative or larger than the number of components!!! */ if ((compno < 0) || (compno >= numcomp)) { - opj_event_msg(j2k->cinfo, EVT_ERROR, + 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(j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + opj_event_msg(p_j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); return; } /* we try to correct */ compno = backup_compno % numcomp; - opj_event_msg(j2k->cinfo, EVT_WARNING, "- trying to adjust this\n" + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- trying to adjust this\n" "- setting component number to %d\n", compno); } @@ -1014,292 +3724,2175 @@ static void j2k_read_qcc(opj_j2k_t *j2k) { backup_compno++; }; #endif /* USE_JPWL */ + if + (l_num_comp <= 256) + { + if + (p_header_size < 1) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading QCC marker\n"); + return 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(p_manager, EVT_ERROR, "Error reading QCC marker\n"); + return 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(p_manager, EVT_ERROR, "Error reading QCC marker\n"); + return false; + } + if + (p_header_size != 0) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading QCC marker\n"); + return false; + } + return true; + +} + + +/** + * Writes the CBD marker (Component bit depth definition) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_cbd( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 i; + OPJ_UINT32 l_cbd_size; + OPJ_BYTE * l_current_data = 00; + opj_image_t *l_image = 00; + opj_image_comp_t * l_comp = 00; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_image = p_j2k->m_image; + l_cbd_size = 6 + p_j2k->m_image->numcomps; + + if + (l_cbd_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) + { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_cbd_size); + if + (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) + { + return false; + } + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_cbd_size; + } - j2k_read_qcx(j2k, compno, len - 2 - (numcomp <= 256 ? 1 : 2)); + l_current_data = p_j2k->m_specific_param.m_encoder.m_header_tile_data; + opj_write_bytes(l_current_data,J2K_MS_CBD,2); /* CBD */ + l_current_data += 2; + opj_write_bytes(l_current_data,l_cbd_size-2,2); /* L_CBD */ + l_current_data += 2; + opj_write_bytes(l_current_data,l_image->numcomps, 2); /* Ncbd */ + l_current_data+=2; + l_comp = l_image->comps; + for + (i=0;i<l_image->numcomps;++i) + { + opj_write_bytes(l_current_data, (l_comp->sgnd << 7) | (l_comp->prec - 1), 1); /* Component bit depth */ + ++l_current_data; + ++l_comp; + } + if + (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_cbd_size,p_manager) != l_cbd_size) + { + return false; + } + return true; } -static void j2k_write_poc(opj_j2k_t *j2k) { - int len, numpchgs, i; +/** + * Reads a CBD marker (Component bit depth definition) + * @param p_header_data the data contained in the CBD box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the CBD marker. + * @param p_manager the user event manager. +*/ +bool j2k_read_cbd ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager) +{ + OPJ_UINT32 l_nb_comp,l_num_comp; + OPJ_UINT32 l_comp_def; + OPJ_UINT32 i; + opj_image_comp_t * l_comp = 00; + + // preconditions + assert(p_header_data != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + l_num_comp = p_j2k->m_image->numcomps; + + if + (p_header_size != (p_j2k->m_image->numcomps + 2)) + { + opj_event_msg(p_manager, EVT_ERROR, "Crror reading CBD marker\n"); + return false; + } + opj_read_bytes(p_header_data,&l_nb_comp,2); /* Ncbd */ + p_header_data+=2; + if + (l_nb_comp != l_num_comp) + { + opj_event_msg(p_manager, EVT_ERROR, "Crror reading CBD marker\n"); + return false; + } - int numcomps = j2k->image->numcomps; + l_comp = p_j2k->m_image->comps; + for + (i=0;i<l_num_comp;++i) + { + opj_read_bytes(p_header_data,&l_comp_def,1); /* Component bit depth */ + ++p_header_data; + l_comp->sgnd = (l_comp_def>>7) & 1; + l_comp->prec = (l_comp_def&0x7f) + 1; + ++l_comp; + } + return true; +} + +/** + * Writes the MCC marker (Multiple Component Collection) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_mcc_record( + opj_j2k_t *p_j2k, + struct opj_simple_mcc_decorrelation_data * p_mcc_record, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 i; + OPJ_UINT32 l_mcc_size; + OPJ_BYTE * l_current_data = 00; + OPJ_UINT32 l_nb_bytes_for_comp; + OPJ_UINT32 l_mask; + OPJ_UINT32 l_tmcc; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + if + (p_mcc_record->m_nb_comps > 255 ) + { + l_nb_bytes_for_comp = 2; + l_mask = 0x8000; + } + else + { + l_nb_bytes_for_comp = 1; + l_mask = 0; + } + + l_mcc_size = p_mcc_record->m_nb_comps * 2 * l_nb_bytes_for_comp + 19; + if + (l_mcc_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) + { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_mcc_size); + if + (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) + { + return false; + } + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_mcc_size; + } + l_current_data = p_j2k->m_specific_param.m_encoder.m_header_tile_data; + opj_write_bytes(l_current_data,J2K_MS_MCC,2); /* MCC */ + l_current_data += 2; + opj_write_bytes(l_current_data,l_mcc_size-2,2); /* Lmcc */ + l_current_data += 2; + + /* first marker */ + opj_write_bytes(l_current_data,0,2); /* Zmcc */ + l_current_data += 2; + opj_write_bytes(l_current_data,p_mcc_record->m_index,1); /* Imcc -> no need for other values, take the first */ + ++l_current_data; + /* only one marker atm */ + opj_write_bytes(l_current_data,0,2); /* Ymcc */ + l_current_data+=2; + opj_write_bytes(l_current_data,1,2); /* Qmcc -> number of collections -> 1 */ + l_current_data+=2; + opj_write_bytes(l_current_data,0x1,1); /* Xmcci type of component transformation -> array based decorrelation */ + ++l_current_data; + + opj_write_bytes(l_current_data,p_mcc_record->m_nb_comps | l_mask,2); /* Nmcci number of input components involved and size for each component offset = 8 bits */ + l_current_data+=2; + + for + (i=0;i<p_mcc_record->m_nb_comps;++i) + { + opj_write_bytes(l_current_data,i,l_nb_bytes_for_comp); /* Cmccij Component offset*/ + l_current_data+=l_nb_bytes_for_comp; + } + + opj_write_bytes(l_current_data,p_mcc_record->m_nb_comps|l_mask,2); /* Mmcci number of output components involved and size for each component offset = 8 bits */ + l_current_data+=2; + for + (i=0;i<p_mcc_record->m_nb_comps;++i) + { + opj_write_bytes(l_current_data,i,l_nb_bytes_for_comp); /* Wmccij Component offset*/ + l_current_data+=l_nb_bytes_for_comp; + } + l_tmcc = ((!p_mcc_record->m_is_irreversible)&1)<<16; + if + (p_mcc_record->m_decorrelation_array) + { + l_tmcc |= p_mcc_record->m_decorrelation_array->m_index; + } + if + (p_mcc_record->m_offset_array) + { + l_tmcc |= ((p_mcc_record->m_offset_array->m_index)<<8); + } + opj_write_bytes(l_current_data,l_tmcc,3); /* Tmcci : use MCT defined as number 1 and irreversible array based. */ + l_current_data+=3; + if + (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_mcc_size,p_manager) != l_mcc_size) + { + return false; + } + return true; +} + + +/** + * Reads a MCC marker (Multiple Component Collection) + * + * @param p_header_data the data contained in the MCC box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the MCC marker. + * @param p_manager the user event manager. +*/ +bool j2k_read_mcc ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 i,j; + OPJ_UINT32 l_tmp; + OPJ_UINT32 l_indix; + opj_tcp_t * l_tcp; + opj_simple_mcc_decorrelation_data_t * l_mcc_record; + opj_mct_data_t * l_mct_data; + OPJ_UINT32 l_nb_collections; + OPJ_UINT32 l_nb_comps; + OPJ_UINT32 l_nb_bytes_by_comp; + + + // preconditions + assert(p_header_data != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + l_tcp = p_j2k->m_specific_param.m_decoder.m_state == J2K_DEC_STATE_TPH ? &p_j2k->m_cp.tcps[p_j2k->m_current_tile_number] : p_j2k->m_specific_param.m_decoder.m_default_tcp; + + if + (p_header_size < 2) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading MCC marker\n"); + return false; + } + + /* first marker */ + opj_read_bytes(p_header_data,&l_tmp,2); /* Zmcc */ + p_header_data += 2; + if + (l_tmp != 0) + { + opj_event_msg(p_manager, EVT_WARNING, "Cannot take in charge multiple data spanning\n"); + return true; + } + if + (p_header_size < 7) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading MCC marker\n"); + return false; + } + opj_read_bytes(p_header_data,&l_indix,1); /* Imcc -> no need for other values, take the first */ + ++p_header_data; - opj_cp_t *cp = j2k->cp; - opj_tcp_t *tcp = &cp->tcps[j2k->curtileno]; - opj_tccp_t *tccp = &tcp->tccps[0]; - opj_cio_t *cio = j2k->cio; + l_mcc_record = l_tcp->m_mcc_records; + for + (i=0;i<l_tcp->m_nb_mcc_records;++i) + { + if + (l_mcc_record->m_index == l_indix) + { + break; + } + ++l_mcc_record; + } + /** NOT FOUND */ + if + (i == l_tcp->m_nb_mcc_records) + { + if + (l_tcp->m_nb_mcc_records == l_tcp->m_nb_max_mcc_records) + { + l_tcp->m_nb_max_mcc_records += J2K_MCC_DEFAULT_NB_RECORDS; + l_tcp->m_mcc_records = opj_realloc(l_tcp->m_mcc_records,l_tcp->m_nb_max_mcc_records * sizeof(opj_simple_mcc_decorrelation_data_t)); + if + (! l_tcp->m_mcc_records) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading MCC marker\n"); + return false; + } + l_mcc_record = l_tcp->m_mcc_records + l_tcp->m_nb_mcc_records; + memset(l_mcc_record,0,(l_tcp->m_nb_max_mcc_records-l_tcp->m_nb_mcc_records) * sizeof(opj_simple_mcc_decorrelation_data_t)); + } + l_mcc_record = l_tcp->m_mcc_records + l_tcp->m_nb_mcc_records; + } + l_mcc_record->m_index = l_indix; + + /* only one marker atm */ + opj_read_bytes(p_header_data,&l_tmp,2); /* Ymcc */ + p_header_data+=2; + if + (l_tmp != 0) + { + opj_event_msg(p_manager, EVT_WARNING, "Cannot take in charge multiple data spanning\n"); + return true; + } + opj_read_bytes(p_header_data,&l_nb_collections,2); /* Qmcc -> number of collections -> 1 */ + p_header_data+=2; + if + (l_nb_collections > 1) + { + opj_event_msg(p_manager, EVT_WARNING, "Cannot take in charge multiple collections\n"); + return true; + } + p_header_size -= 7; + for + (i=0;i<l_nb_collections;++i) + { + if + (p_header_size < 3) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading MCC marker\n"); + return false; + } + opj_read_bytes(p_header_data,&l_tmp,1); /* Xmcci type of component transformation -> array based decorrelation */ + ++p_header_data; + if + (l_tmp != 1) + { + opj_event_msg(p_manager, EVT_WARNING, "Cannot take in charge collections other than array decorrelation\n"); + return true; + } + opj_read_bytes(p_header_data,&l_nb_comps,2); + p_header_data+=2; + p_header_size-=3; + l_nb_bytes_by_comp = 1 + (l_nb_comps>>15); + l_mcc_record->m_nb_comps = l_nb_comps & 0x7fff; + if + (p_header_size < (l_nb_bytes_by_comp * l_mcc_record->m_nb_comps + 2)) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading MCC marker\n"); + return false; + } + p_header_size -= (l_nb_bytes_by_comp * l_mcc_record->m_nb_comps + 2); + for + (j=0;j<l_mcc_record->m_nb_comps;++j) + { + opj_read_bytes(p_header_data,&l_tmp,l_nb_bytes_by_comp); /* Cmccij Component offset*/ + p_header_data+=l_nb_bytes_by_comp; + if + (l_tmp != j) + { + opj_event_msg(p_manager, EVT_WARNING, "Cannot take in charge collections with indix shuffle\n"); + return true; + } + } + opj_read_bytes(p_header_data,&l_nb_comps,2); + p_header_data+=2; + l_nb_bytes_by_comp = 1 + (l_nb_comps>>15); + l_nb_comps &= 0x7fff; + if + (l_nb_comps != l_mcc_record->m_nb_comps) + { + opj_event_msg(p_manager, EVT_WARNING, "Cannot take in charge collections without same number of indixes\n"); + return true; + } + if + (p_header_size < (l_nb_bytes_by_comp * l_mcc_record->m_nb_comps + 3)) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading MCC marker\n"); + return false; + } + p_header_size -= (l_nb_bytes_by_comp * l_mcc_record->m_nb_comps + 3); + for + (j=0;j<l_mcc_record->m_nb_comps;++j) + { + opj_read_bytes(p_header_data,&l_tmp,l_nb_bytes_by_comp); /* Wmccij Component offset*/ + p_header_data+=l_nb_bytes_by_comp; + if + (l_tmp != j) + { + opj_event_msg(p_manager, EVT_WARNING, "Cannot take in charge collections with indix shuffle\n"); + return true; + } + } + opj_read_bytes(p_header_data,&l_tmp,3); /* Wmccij Component offset*/ + p_header_data += 3; + l_mcc_record->m_is_irreversible = ! ((l_tmp>>16) & 1); + l_mcc_record->m_decorrelation_array = 00; + l_mcc_record->m_offset_array = 00; + l_indix = l_tmp & 0xff; + if + (l_indix != 0) + { + l_mct_data = l_tcp->m_mct_records; + for + (j=0;j<l_tcp->m_nb_mct_records;++j) + { + if + (l_mct_data->m_index == l_indix) + { + l_mcc_record->m_decorrelation_array = l_mct_data; + break; + } + ++l_mct_data; + } + if + (l_mcc_record->m_decorrelation_array == 00) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading MCC marker\n"); + return false; + } + } + l_indix = (l_tmp >> 8) & 0xff; + if + (l_indix != 0) + { + l_mct_data = l_tcp->m_mct_records; + for + (j=0;j<l_tcp->m_nb_mct_records;++j) + { + if + (l_mct_data->m_index == l_indix) + { + l_mcc_record->m_offset_array = l_mct_data; + break; + } + ++l_mct_data; + } + if + (l_mcc_record->m_offset_array == 00) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading MCC marker\n"); + return false; + } + } + } + if + (p_header_size != 0) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading MCC marker\n"); + return false; + } + ++l_tcp->m_nb_mcc_records; + return true; +} - numpchgs = 1 + tcp->numpocs; - cio_write(cio, J2K_MS_POC, 2); /* POC */ - len = 2 + (5 + 2 * (numcomps <= 256 ? 1 : 2)) * numpchgs; - cio_write(cio, len, 2); /* Lpoc */ - for (i = 0; i < numpchgs; i++) { - opj_poc_t *poc = &tcp->pocs[i]; - cio_write(cio, poc->resno0, 1); /* RSpoc_i */ - cio_write(cio, poc->compno0, (numcomps <= 256 ? 1 : 2)); /* CSpoc_i */ - cio_write(cio, poc->layno1, 2); /* LYEpoc_i */ - poc->layno1 = int_min(poc->layno1, tcp->numlayers); - cio_write(cio, poc->resno1, 1); /* REpoc_i */ - poc->resno1 = int_min(poc->resno1, tccp->numresolutions); - cio_write(cio, poc->compno1, (numcomps <= 256 ? 1 : 2)); /* CEpoc_i */ - poc->compno1 = int_min(poc->compno1, numcomps); - cio_write(cio, poc->prg, 1); /* Ppoc_i */ +/** + * Writes the MCT marker (Multiple Component Transform) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_mct_record( + opj_j2k_t *p_j2k, + opj_mct_data_t * p_mct_record, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 l_mct_size; + OPJ_BYTE * l_current_data = 00; + OPJ_UINT32 l_tmp; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_mct_size = 10 + p_mct_record->m_data_size; + if + (l_mct_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) + { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_mct_size); + if + (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) + { + return false; + } + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_mct_size; + } + + l_current_data = p_j2k->m_specific_param.m_encoder.m_header_tile_data; + + opj_write_bytes(l_current_data,J2K_MS_MCT,2); /* MCT */ + l_current_data += 2; + opj_write_bytes(l_current_data,l_mct_size-2,2); /* Lmct */ + l_current_data += 2; + opj_write_bytes(l_current_data,0,2); /* Zmct */ + l_current_data += 2; + /* only one marker atm */ + l_tmp = (p_mct_record->m_index & 0xff) | (p_mct_record->m_array_type << 8) | (p_mct_record->m_element_type << 10); + opj_write_bytes(l_current_data,l_tmp,2); + l_current_data += 2; + opj_write_bytes(l_current_data,0,2); /* Ymct */ + l_current_data+=2; + + memcpy(l_current_data,p_mct_record->m_data,p_mct_record->m_data_size); + if + (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_mct_size,p_manager) != l_mct_size) + { + return false; } + return true; } -static void j2k_read_poc(opj_j2k_t *j2k) { - int len, numpchgs, i, old_poc; +/** + * Reads a MCT marker (Multiple Component Transform) + * + * @param p_header_data the data contained in the MCT box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the MCT marker. + * @param p_manager the user event manager. +*/ +bool j2k_read_mct ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 i; + opj_tcp_t *l_tcp = 00; + OPJ_UINT32 l_tmp; + OPJ_UINT32 l_indix; + opj_mct_data_t * l_mct_data; + + // preconditions + assert(p_header_data != 00); + assert(p_j2k != 00); + + l_tcp = p_j2k->m_specific_param.m_decoder.m_state == J2K_DEC_STATE_TPH ? &p_j2k->m_cp.tcps[p_j2k->m_current_tile_number] : p_j2k->m_specific_param.m_decoder.m_default_tcp; - int numcomps = j2k->image->numcomps; + if + (p_header_size < 2) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading MCT marker\n"); + return false; + } + /* first marker */ + opj_read_bytes(p_header_data,&l_tmp,2); /* Zmct */ + p_header_data += 2; + if + (l_tmp != 0) + { + opj_event_msg(p_manager, EVT_WARNING, "Cannot take in charge mct data within multiple MCT records\n"); + return true; + } + if + (p_header_size <= 6) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading MCT marker\n"); + return false; + } + opj_read_bytes(p_header_data,&l_tmp,2); /* Imct -> no need for other values, take the first, type is double with decorrelation x0000 1101 0000 0000*/ + p_header_data += 2; - opj_cp_t *cp = j2k->cp; - opj_tcp_t *tcp = j2k->state == J2K_STATE_TPH ? &cp->tcps[j2k->curtileno] : j2k->default_tcp; - opj_cio_t *cio = j2k->cio; + l_indix = l_tmp & 0xff; + l_mct_data = l_tcp->m_mct_records; + for + (i=0;i<l_tcp->m_nb_mct_records;++i) + { + if + (l_mct_data->m_index == l_indix) + { + break; + } + ++l_mct_data; + } + /* NOT FOUND */ + if + (i == l_tcp->m_nb_mct_records) + { + if + (l_tcp->m_nb_mct_records == l_tcp->m_nb_max_mct_records) + { + l_tcp->m_nb_max_mct_records += J2K_MCT_DEFAULT_NB_RECORDS; + l_tcp->m_mct_records = opj_realloc(l_tcp->m_mct_records,l_tcp->m_nb_max_mct_records * sizeof(opj_mct_data_t)); + if + (! l_tcp->m_mct_records) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading MCT marker\n"); + return false; + } + l_mct_data = l_tcp->m_mct_records + l_tcp->m_nb_mct_records; + memset(l_mct_data ,0,(l_tcp->m_nb_max_mct_records - l_tcp->m_nb_mct_records) * sizeof(opj_mct_data_t)); + } + l_mct_data = l_tcp->m_mct_records + l_tcp->m_nb_mct_records; + } + if + (l_mct_data->m_data) + { + opj_free(l_mct_data->m_data); + l_mct_data->m_data = 00; + } + l_mct_data->m_index = l_indix; + l_mct_data->m_array_type = (l_tmp >> 8) & 3; + l_mct_data->m_element_type = (l_tmp >> 10) & 3; + + opj_read_bytes(p_header_data,&l_tmp,2); /* Ymct */ + p_header_data+=2; + if + (l_tmp != 0) + { + opj_event_msg(p_manager, EVT_WARNING, "Cannot take in charge multiple MCT markers\n"); + return true; + } + p_header_size -= 6; + l_mct_data->m_data = opj_malloc(p_header_size); + if + (! l_mct_data->m_data) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading MCT marker\n"); + return false; + } + memcpy(l_mct_data->m_data,p_header_data,p_header_size); + l_mct_data->m_data_size = p_header_size; + ++l_tcp->m_nb_mct_records; + return true; +} + +bool j2k_setup_mct_encoding (opj_tcp_t * p_tcp,opj_image_t * p_image) +{ + OPJ_UINT32 i; + OPJ_UINT32 l_indix = 1; + opj_mct_data_t * l_mct_deco_data = 00,* l_mct_offset_data = 00; + opj_simple_mcc_decorrelation_data_t * l_mcc_data; + OPJ_UINT32 l_mct_size,l_nb_elem; + OPJ_FLOAT32 * l_data, * l_current_data; + opj_tccp_t * l_tccp; + + // preconditions + assert(p_tcp != 00); + + if + (p_tcp->mct != 2) + { + return true; + } - old_poc = tcp->POC ? tcp->numpocs + 1 : 0; - tcp->POC = 1; - len = cio_read(cio, 2); /* Lpoc */ - numpchgs = (len - 2) / (5 + 2 * (numcomps <= 256 ? 1 : 2)); + if + (p_tcp->m_mct_decoding_matrix) + { + if + (p_tcp->m_nb_mct_records == p_tcp->m_nb_max_mct_records) + { + p_tcp->m_nb_max_mct_records += J2K_MCT_DEFAULT_NB_RECORDS; + p_tcp->m_mct_records = opj_realloc(p_tcp->m_mct_records,p_tcp->m_nb_max_mct_records * sizeof(opj_mct_data_t)); + if + (! p_tcp->m_mct_records) + { + return false; + } + l_mct_deco_data = p_tcp->m_mct_records + p_tcp->m_nb_mct_records; + memset(l_mct_deco_data ,0,(p_tcp->m_nb_max_mct_records - p_tcp->m_nb_mct_records) * sizeof(opj_mct_data_t)); + } + l_mct_deco_data = p_tcp->m_mct_records + p_tcp->m_nb_mct_records; + + if + (l_mct_deco_data->m_data) + { + opj_free(l_mct_deco_data->m_data); + l_mct_deco_data->m_data = 00; + } + l_mct_deco_data->m_index = l_indix++; + l_mct_deco_data->m_array_type = MCT_TYPE_DECORRELATION; + l_mct_deco_data->m_element_type = MCT_TYPE_FLOAT; + l_nb_elem = p_image->numcomps * p_image->numcomps; + l_mct_size = l_nb_elem * MCT_ELEMENT_SIZE[l_mct_deco_data->m_element_type]; + l_mct_deco_data->m_data = opj_malloc(l_mct_size ); + if + (! l_mct_deco_data->m_data) + { + return false; + } + j2k_mct_write_functions_from_float[l_mct_deco_data->m_element_type](p_tcp->m_mct_decoding_matrix,l_mct_deco_data->m_data,l_nb_elem); + l_mct_deco_data->m_data_size = l_mct_size; + ++p_tcp->m_nb_mct_records; + } + + if + (p_tcp->m_nb_mct_records == p_tcp->m_nb_max_mct_records) + { + p_tcp->m_nb_max_mct_records += J2K_MCT_DEFAULT_NB_RECORDS; + p_tcp->m_mct_records = opj_realloc(p_tcp->m_mct_records,p_tcp->m_nb_max_mct_records * sizeof(opj_mct_data_t)); + if + (! p_tcp->m_mct_records) + { + return false; + } + l_mct_offset_data = p_tcp->m_mct_records + p_tcp->m_nb_mct_records; + memset(l_mct_offset_data ,0,(p_tcp->m_nb_max_mct_records - p_tcp->m_nb_mct_records) * sizeof(opj_mct_data_t)); + if + (l_mct_deco_data) + { + l_mct_deco_data = l_mct_offset_data - 1; + } + } + l_mct_offset_data = p_tcp->m_mct_records + p_tcp->m_nb_mct_records; + if + (l_mct_offset_data->m_data) + { + opj_free(l_mct_offset_data->m_data); + l_mct_offset_data->m_data = 00; + } - for (i = old_poc; i < numpchgs + old_poc; i++) { - opj_poc_t *poc; - poc = &tcp->pocs[i]; - poc->resno0 = cio_read(cio, 1); /* RSpoc_i */ - poc->compno0 = cio_read(cio, numcomps <= 256 ? 1 : 2); /* CSpoc_i */ - poc->layno1 = cio_read(cio, 2); /* LYEpoc_i */ - poc->resno1 = cio_read(cio, 1); /* REpoc_i */ - poc->compno1 = int_min( - cio_read(cio, numcomps <= 256 ? 1 : 2), (unsigned int) numcomps); /* CEpoc_i */ - poc->prg = (OPJ_PROG_ORDER)cio_read(cio, 1); /* Ppoc_i */ + l_mct_offset_data->m_index = l_indix++; + l_mct_offset_data->m_array_type = MCT_TYPE_OFFSET; + l_mct_offset_data->m_element_type = MCT_TYPE_FLOAT; + l_nb_elem = p_image->numcomps; + l_mct_size = l_nb_elem * MCT_ELEMENT_SIZE[l_mct_offset_data->m_element_type]; + l_mct_offset_data->m_data = opj_malloc(l_mct_size ); + if + (! l_mct_offset_data->m_data) + { + return false; + } + l_data = opj_malloc(l_nb_elem * sizeof(OPJ_FLOAT32)); + if + (! l_data) + { + opj_free(l_mct_offset_data->m_data); + l_mct_offset_data->m_data = 00; + return false; + } + l_tccp = p_tcp->tccps; + l_current_data = l_data; + for + (i=0;i<l_nb_elem;++i) + { + *(l_current_data++) = (OPJ_FLOAT32) (l_tccp->m_dc_level_shift); + ++l_tccp; } + j2k_mct_write_functions_from_float[l_mct_offset_data->m_element_type](l_data,l_mct_offset_data->m_data,l_nb_elem); + opj_free(l_data); + l_mct_offset_data->m_data_size = l_mct_size; + ++p_tcp->m_nb_mct_records; - tcp->numpocs = numpchgs + old_poc - 1; + if + (p_tcp->m_nb_mcc_records == p_tcp->m_nb_max_mcc_records) + { + p_tcp->m_nb_max_mcc_records += J2K_MCT_DEFAULT_NB_RECORDS; + p_tcp->m_mcc_records = opj_realloc(p_tcp->m_mcc_records,p_tcp->m_nb_max_mcc_records * sizeof(opj_simple_mcc_decorrelation_data_t)); + if + (! p_tcp->m_mcc_records) + { + return false; + } + l_mcc_data = p_tcp->m_mcc_records + p_tcp->m_nb_mcc_records; + memset(l_mcc_data ,0,(p_tcp->m_nb_max_mcc_records - p_tcp->m_nb_mcc_records) * sizeof(opj_simple_mcc_decorrelation_data_t)); + + } + l_mcc_data = p_tcp->m_mcc_records + p_tcp->m_nb_mcc_records; + l_mcc_data->m_decorrelation_array = l_mct_deco_data; + l_mcc_data->m_is_irreversible = 1; + l_mcc_data->m_nb_comps = p_image->numcomps; + l_mcc_data->m_index = l_indix++; + l_mcc_data->m_offset_array = l_mct_offset_data; + ++p_tcp->m_nb_mcc_records; + return true; +} + +/** + * Writes the MCO marker (Multiple component transformation ordering) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_mco( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_BYTE * l_current_data = 00; + OPJ_UINT32 l_mco_size; + opj_tcp_t * l_tcp = 00; + opj_simple_mcc_decorrelation_data_t * l_mcc_record; + OPJ_UINT32 i; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_tcp =&(p_j2k->m_cp.tcps[p_j2k->m_current_tile_number]); + l_current_data = p_j2k->m_specific_param.m_encoder.m_header_tile_data; + l_mco_size = 5 + l_tcp->m_nb_mcc_records; + if + (l_mco_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) + { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_mco_size); + if + (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) + { + return false; + } + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_mco_size; + } + + opj_write_bytes(l_current_data,J2K_MS_MCO,2); /* MCO */ + l_current_data += 2; + opj_write_bytes(l_current_data,l_mco_size-2,2); /* Lmco */ + l_current_data += 2; + opj_write_bytes(l_current_data,l_tcp->m_nb_mcc_records,1); /* Nmco : only one tranform stage*/ + ++l_current_data; + + l_mcc_record = l_tcp->m_mcc_records; + for + (i=0;i<l_tcp->m_nb_mcc_records;++i) + { + opj_write_bytes(l_current_data,l_mcc_record->m_index,1); /* Imco -> use the mcc indicated by 1*/ + ++l_current_data; + ++l_mcc_record; + } + + if + (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_mco_size,p_manager) != l_mco_size) + { + return false; + } + return true; } +/** + * Reads a MCO marker (Multiple Component Transform Ordering) + * + * @param p_header_data the data contained in the MCO box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the MCO marker. + * @param p_manager the user event manager. +*/ +bool j2k_read_mco ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 l_tmp, i; + OPJ_UINT32 l_nb_stages; + opj_tcp_t * l_tcp; + opj_tccp_t * l_tccp; + opj_image_t * l_image; + opj_image_comp_t * l_img_comp; + + // preconditions + assert(p_header_data != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + l_image = p_j2k->m_image; + l_tcp = p_j2k->m_specific_param.m_decoder.m_state == J2K_DEC_STATE_TPH ? &p_j2k->m_cp.tcps[p_j2k->m_current_tile_number] : p_j2k->m_specific_param.m_decoder.m_default_tcp; + if + (p_header_size < 1) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading MCO marker\n"); + return false; + } -static void j2k_read_crg(opj_j2k_t *j2k) { - int len, i, Xcrg_i, Ycrg_i; + opj_read_bytes(p_header_data,&l_nb_stages,1); /* Nmco : only one tranform stage*/ + ++p_header_data; + if + (l_nb_stages > 1) + { + opj_event_msg(p_manager, EVT_WARNING, "Cannot take in charge multiple transformation stages.\n"); + return true; + } + if + (p_header_size != l_nb_stages + 1) + { + opj_event_msg(p_manager, EVT_WARNING, "Error reading MCO marker\n"); + return false; + } - opj_cio_t *cio = j2k->cio; - int numcomps = j2k->image->numcomps; + l_tccp = l_tcp->tccps; + l_img_comp = l_image->comps; + for + (i=0;i<l_image->numcomps;++i) + { + l_tccp->m_dc_level_shift = 0; + ++l_tccp; + } + if + (l_tcp->m_mct_decoding_matrix) + { + opj_free(l_tcp->m_mct_decoding_matrix); + l_tcp->m_mct_decoding_matrix = 00; + } + + for + (i=0;i<l_nb_stages;++i) + { + opj_read_bytes(p_header_data,&l_tmp,1); + ++p_header_data; + if + (! j2k_add_mct(l_tcp,p_j2k->m_image,l_tmp)) + { + return false; + } + } + return true; +} + +bool j2k_add_mct(opj_tcp_t * p_tcp,opj_image_t * p_image, OPJ_UINT32 p_index) +{ + OPJ_UINT32 i; + opj_simple_mcc_decorrelation_data_t * l_mcc_record; + opj_mct_data_t * l_deco_array, * l_offset_array; + OPJ_UINT32 l_data_size,l_mct_size, l_offset_size; + OPJ_UINT32 l_nb_elem; + OPJ_UINT32 * l_offset_data, * l_current_offset_data; + opj_tccp_t * l_tccp; + + + // preconditions + assert(p_tcp != 00); + + l_mcc_record = p_tcp->m_mcc_records; + for + (i=0;i<p_tcp->m_nb_mcc_records;++i) + { + if + (l_mcc_record->m_index == p_index) + { + break; + } + } + if + (i==p_tcp->m_nb_mcc_records) + { + /** element discarded **/ + return true; + } + if + (l_mcc_record->m_nb_comps != p_image->numcomps) + { + /** do not support number of comps != image */ + return true; + } + l_deco_array = l_mcc_record->m_decorrelation_array; + if + (l_deco_array) + { + l_data_size = MCT_ELEMENT_SIZE[l_deco_array->m_element_type] * p_image->numcomps * p_image->numcomps; + if + (l_deco_array->m_data_size != l_data_size) + { + return false; + } + l_nb_elem = p_image->numcomps * p_image->numcomps; + l_mct_size = l_nb_elem * sizeof(OPJ_FLOAT32); + p_tcp->m_mct_decoding_matrix = opj_malloc(l_mct_size); + if + (! p_tcp->m_mct_decoding_matrix ) + { + return false; + } + j2k_mct_read_functions_to_float[l_deco_array->m_element_type](l_deco_array->m_data,p_tcp->m_mct_decoding_matrix,l_nb_elem); + } + l_offset_array = l_mcc_record->m_offset_array; + if + (l_offset_array) + { + l_data_size = MCT_ELEMENT_SIZE[l_offset_array->m_element_type] * p_image->numcomps; + if + (l_offset_array->m_data_size != l_data_size) + { + return false; + } + l_nb_elem = p_image->numcomps; + l_offset_size = l_nb_elem * sizeof(OPJ_UINT32); + l_offset_data = opj_malloc(l_offset_size); + if + (! l_offset_data ) + { + return false; + } + j2k_mct_read_functions_to_int32[l_offset_array->m_element_type](l_offset_array->m_data,l_offset_data,l_nb_elem); + l_tccp = p_tcp->tccps; + l_current_offset_data = l_offset_data; + for + (i=0;i<p_image->numcomps;++i) + { + l_tccp->m_dc_level_shift = *(l_current_offset_data++); + ++l_tccp; + } + opj_free(l_offset_data); + } + return true; +} + +/** + * Writes the MCT marker (Multiple Component Transform) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_mct_data_group( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 i; + opj_simple_mcc_decorrelation_data_t * l_mcc_record; + opj_mct_data_t * l_mct_record; + opj_tcp_t * l_tcp; + + // preconditions + assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); + + if + (! j2k_write_cbd(p_j2k,p_stream,p_manager)) + { + return false; + } + l_tcp = &(p_j2k->m_cp.tcps[p_j2k->m_current_tile_number]); + l_mct_record = l_tcp->m_mct_records; + for + (i=0;i<l_tcp->m_nb_mct_records;++i) + { + if + (! j2k_write_mct_record(p_j2k,l_mct_record,p_stream,p_manager)) + { + return false; + } + ++l_mct_record; + } + l_mcc_record = l_tcp->m_mcc_records; + for + (i=0;i<l_tcp->m_nb_mcc_records;++i) + { + if + (! j2k_write_mcc_record(p_j2k,l_mcc_record,p_stream,p_manager)) + { + return false; + } + ++l_mcc_record; + } + if + (! j2k_write_mco(p_j2k,p_stream,p_manager)) + { + return false; + } + return true; +} + + +/** + * Writes the POC marker (Progression Order Change) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_poc( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 l_nb_comp; + OPJ_UINT32 l_nb_poc; + OPJ_UINT32 l_poc_size; + OPJ_UINT32 l_written_size = 0; + opj_tcp_t *l_tcp = 00; + opj_tccp_t *l_tccp = 00; + OPJ_UINT32 l_poc_room; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_tcp = &p_j2k->m_cp.tcps[p_j2k->m_current_tile_number]; + l_tccp = &l_tcp->tccps[0]; + l_nb_comp = p_j2k->m_image->numcomps; + l_nb_poc = 1 + l_tcp->numpocs; + if + (l_nb_comp <= 256) + { + l_poc_room = 1; + } + else + { + l_poc_room = 2; + } + l_poc_size = 4 + (5 + 2 * l_poc_room) * l_nb_poc; + if + (l_poc_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) + { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_poc_size); + if + (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) + { + return false; + } + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_poc_size; + } + + j2k_write_poc_in_memory(p_j2k,p_j2k->m_specific_param.m_encoder.m_header_tile_data,&l_written_size,p_manager); + + if + (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_poc_size,p_manager) != l_poc_size) + { + return false; + } + return true; +} + + +/** + * Writes EPC ???? + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_epc( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + opj_codestream_info_t * l_info = 00; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_info = p_j2k->cstr_info; + if + (l_info) + { + l_info->codestream_size = opj_stream_tell(p_stream); + /* UniPG>> */ + /* The following adjustment is done to adjust the codestream size */ + /* if SOD is not at 0 in the buffer. Useful in case of JP2, where */ + /* the first bunch of bytes is not in the codestream */ + l_info->codestream_size -= l_info->main_head_start; + /* <<UniPG */ + } + +#ifdef USE_JPWL + /* + preparation of JPWL marker segments + */ + if(cp->epc_on) { + + /* encode according to JPWL */ + jpwl_encode(p_j2k, p_stream, image); + + } +#endif /* USE_JPWL */ + return true; +} + + +/** + * Gets the maximum size taken by the writting of a POC. + */ +OPJ_UINT32 j2k_get_max_poc_size(opj_j2k_t *p_j2k) +{ + opj_tcp_t * l_tcp = 00; + OPJ_UINT32 l_nb_tiles = 0; + OPJ_UINT32 l_max_poc = 0; + OPJ_UINT32 i; + + l_tcp = p_j2k->m_cp.tcps; + l_nb_tiles = p_j2k->m_cp.th * p_j2k->m_cp.tw; + + for + (i=0;i<l_nb_tiles;++i) + { + l_max_poc = uint_max(l_max_poc,l_tcp->numpocs); + ++l_tcp; + } + ++l_max_poc; + return 4 + 9 * l_max_poc; +} + + +/** + * Writes the POC marker (Progression Order Change) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +void j2k_write_poc_in_memory( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 i; + OPJ_BYTE * l_current_data = 00; + OPJ_UINT32 l_nb_comp; + OPJ_UINT32 l_nb_poc; + OPJ_UINT32 l_poc_size; + opj_image_t *l_image = 00; + opj_tcp_t *l_tcp = 00; + opj_tccp_t *l_tccp = 00; + opj_poc_t *l_current_poc = 00; + OPJ_UINT32 l_poc_room; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + + l_tcp = &p_j2k->m_cp.tcps[p_j2k->m_current_tile_number]; + l_tccp = &l_tcp->tccps[0]; + l_image = p_j2k->m_image; + l_nb_comp = l_image->numcomps; + l_nb_poc = 1 + l_tcp->numpocs; + if + (l_nb_comp <= 256) + { + l_poc_room = 1; + } + else + { + l_poc_room = 2; + } + l_poc_size = 4 + (5 + 2 * l_poc_room) * l_nb_poc; + + l_current_data = p_data; + + opj_write_bytes(l_current_data,J2K_MS_POC,2); /* POC */ + l_current_data += 2; + opj_write_bytes(l_current_data,l_poc_size-2,2); /* Lpoc */ + l_current_data += 2; - len = cio_read(cio, 2); /* Lcrg */ - for (i = 0; i < numcomps; i++) { - Xcrg_i = cio_read(cio, 2); /* Xcrg_i */ - Ycrg_i = cio_read(cio, 2); /* Ycrg_i */ + l_current_poc = l_tcp->pocs; + for + (i = 0; i < l_nb_poc; ++i) + { + opj_write_bytes(l_current_data,l_current_poc->resno0,1); /* RSpoc_i */ + ++l_current_data; + opj_write_bytes(l_current_data,l_current_poc->compno0,l_poc_room); /* CSpoc_i */ + l_current_data+=l_poc_room; + opj_write_bytes(l_current_data,l_current_poc->layno1,2); /* LYEpoc_i */ + l_current_data+=2; + opj_write_bytes(l_current_data,l_current_poc->resno1,1); /* REpoc_i */ + ++l_current_data; + opj_write_bytes(l_current_data,l_current_poc->compno1,l_poc_room); /* CEpoc_i */ + l_current_data+=l_poc_room; + opj_write_bytes(l_current_data,l_current_poc->prg,1); /* Ppoc_i */ + ++l_current_data; + + /* change the value of the max layer according to the actual number of layers in the file, components and resolutions*/ + l_current_poc->layno1 = int_min(l_current_poc->layno1, l_tcp->numlayers); + l_current_poc->resno1 = int_min(l_current_poc->resno1, l_tccp->numresolutions); + l_current_poc->compno1 = int_min(l_current_poc->compno1, l_nb_comp); + ++l_current_poc; } + * p_data_written = l_poc_size; } -static void j2k_read_tlm(opj_j2k_t *j2k) { - int len, Ztlm, Stlm, ST, SP, tile_tlm, i; - long int Ttlm_i, Ptlm_i; - opj_cio_t *cio = j2k->cio; +/** + * 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. +*/ +bool j2k_read_poc ( + opj_j2k_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_t *l_cp = 00; + opj_tcp_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(p_manager, EVT_ERROR, "Error reading POC marker\n"); + return false; + } + + l_cp = &(p_j2k->m_cp); + l_tcp = (p_j2k->m_specific_param.m_decoder.m_state == 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 true; +} + +/** + * Writes the RGN marker (Region Of Interest) + * + * @param p_tile_no the tile to output + * @param p_comp_no the component to output + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_rgn( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_BYTE * l_current_data = 00; + OPJ_UINT32 l_nb_comp; + OPJ_UINT32 l_rgn_size; + opj_image_t *l_image = 00; + opj_cp_t *l_cp = 00; + opj_tcp_t *l_tcp = 00; + opj_tccp_t *l_tccp = 00; + OPJ_UINT32 l_comp_room; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_cp = &(p_j2k->m_cp); + l_tcp = &l_cp->tcps[p_tile_no]; + l_tccp = &l_tcp->tccps[p_comp_no]; + + l_nb_comp = l_image->numcomps; + + if + (l_nb_comp <= 256) + { + l_comp_room = 1; + } + else + { + l_comp_room = 2; + } + l_rgn_size = 6 + l_comp_room; - len = cio_read(cio, 2); /* Ltlm */ - Ztlm = cio_read(cio, 1); /* Ztlm */ - Stlm = cio_read(cio, 1); /* Stlm */ - ST = ((Stlm >> 4) & 0x01) + ((Stlm >> 4) & 0x02); - SP = (Stlm >> 6) & 0x01; - tile_tlm = (len - 4) / ((SP + 1) * 2 + ST); - for (i = 0; i < tile_tlm; i++) { - Ttlm_i = cio_read(cio, ST); /* Ttlm_i */ - Ptlm_i = cio_read(cio, SP ? 4 : 2); /* Ptlm_i */ + l_current_data = p_j2k->m_specific_param.m_encoder.m_header_tile_data; + + opj_write_bytes(l_current_data,J2K_MS_RGN,2); /* RGN */ + l_current_data += 2; + opj_write_bytes(l_current_data,l_rgn_size-2,2); /* Lrgn */ + l_current_data += 2; + opj_write_bytes(l_current_data,p_comp_no,l_comp_room); /* Crgn */ + l_current_data+=l_comp_room; + opj_write_bytes(l_current_data, 0,1); /* Srgn */ + ++l_current_data; + opj_write_bytes(l_current_data, l_tccp->roishift,1); /* SPrgn */ + ++l_current_data; + + if + (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_rgn_size,p_manager) != l_rgn_size) + { + return false; } + return true; } -static void j2k_read_plm(opj_j2k_t *j2k) { - int len, i, Zplm, Nplm, add, packet_len = 0; +/** + * 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. +*/ +bool j2k_read_rgn ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 l_nb_comp; + opj_image_t * l_image = 00; + + opj_cp_t *l_cp = 00; + opj_tcp_t *l_tcp = 00; + OPJ_UINT32 l_comp_room; + OPJ_UINT32 l_comp_no; + OPJ_UINT32 l_roi_sty; + + // preconditions + assert(p_header_data != 00); + assert(p_j2k != 00); + assert(p_manager != 00); - opj_cio_t *cio = j2k->cio; + 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; + } + if + (p_header_size != 2 + l_comp_room) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading RGN marker\n"); + return false; + } - len = cio_read(cio, 2); /* Lplm */ - Zplm = cio_read(cio, 1); /* Zplm */ - len -= 3; - while (len > 0) { - Nplm = cio_read(cio, 4); /* Nplm */ - len -= 4; - for (i = Nplm; i > 0; i--) { - add = cio_read(cio, 1); - len--; - packet_len = (packet_len << 7) + add; /* Iplm_ij */ - if ((add & 0x80) == 0) { - /* New packet */ - packet_len = 0; + l_cp = &(p_j2k->m_cp); + l_tcp = (p_j2k->m_specific_param.m_decoder.m_state == 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; } - if (len <= 0) - break; } + }; +#endif /* USE_JPWL */ + + opj_read_bytes(p_header_data,(OPJ_UINT32 *) (&(l_tcp->tccps[l_comp_no].roishift)),1); /* SPrgn */ + ++p_header_data; + return true; + +} + +/** + * Writes the TLM marker (Tile Length Marker) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_tlm( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_BYTE * l_current_data = 00; + OPJ_UINT32 l_tlm_size; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_tlm_size = 6 + (5*p_j2k->m_specific_param.m_encoder.m_total_tile_parts); + if + (l_tlm_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) + { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_tlm_size); + if + (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) + { + return false; + } + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_tlm_size; + } + l_current_data = p_j2k->m_specific_param.m_encoder.m_header_tile_data; + + /* change the way data is written to avoid seeking if possible */ + // TODO + p_j2k->m_specific_param.m_encoder.m_tlm_start = opj_stream_tell(p_stream); + + opj_write_bytes(l_current_data,J2K_MS_TLM,2); /* TLM */ + l_current_data += 2; + opj_write_bytes(l_current_data,l_tlm_size-2,2); /* Lpoc */ + l_current_data += 2; + opj_write_bytes(l_current_data,0,1); /* Ztlm=0*/ + ++l_current_data; + opj_write_bytes(l_current_data,0x50,1); /* Stlm ST=1(8bits-255 tiles max),SP=1(Ptlm=32bits) */ + ++l_current_data; + /* do nothing on the 5 * l_j2k->m_specific_param.m_encoder.m_total_tile_parts remaining data */ + + if + (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_tlm_size,p_manager) != l_tlm_size) + { + return false; } + return true; } -static void j2k_read_plt(opj_j2k_t *j2k) { - int len, i, Zplt, packet_len = 0, add; +/** + * 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. +*/ +bool j2k_read_tlm ( + opj_j2k_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); - opj_cio_t *cio = j2k->cio; + if + (p_header_size < 2) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading TLM marker\n"); + return 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; - len = cio_read(cio, 2); /* Lplt */ - Zplt = cio_read(cio, 1); /* Zplt */ - for (i = len - 3; i > 0; i--) { - add = cio_read(cio, 1); - packet_len = (packet_len << 7) + add; /* Iplt_i */ - if ((add & 0x80) == 0) { - /* New packet */ - packet_len = 0; + 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(p_manager, EVT_ERROR, "Error reading TLM marker\n"); + return 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 true; +} + +/** + * 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. +*/ +bool j2k_read_crg ( + opj_j2k_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(p_manager, EVT_ERROR, "Error reading CRG marker\n"); + return 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 true; +} + +/** + * 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. +*/ +bool j2k_read_plm ( + opj_j2k_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(p_manager, EVT_ERROR, "Error reading PLM marker\n"); + return 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 true; } -static void j2k_read_ppm(opj_j2k_t *j2k) { - int len, Z_ppm, i, j; - int N_ppm; +/** + * 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. +*/ +bool j2k_read_plt ( + opj_j2k_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(p_manager, EVT_ERROR, "Error reading PLM marker\n"); + return 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(p_manager, EVT_ERROR, "Error reading PLM marker\n"); + return false; + } + return true; +} - opj_cp_t *cp = j2k->cp; - opj_cio_t *cio = j2k->cio; +/** + * 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. +*/ +bool j2k_read_ppm ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ) +{ + + opj_cp_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(p_manager, EVT_ERROR, "Error reading RGN marker\n"); + return false; + } + l_cp = &(p_j2k->m_cp); + l_cp->ppm = 1; - len = cio_read(cio, 2); - cp->ppm = 1; + opj_read_bytes(p_header_data,&l_Z_ppm,1); /* Z_ppm */ + ++p_header_data; + --p_header_size; - Z_ppm = cio_read(cio, 1); /* Z_ppm */ - len -= 3; - while (len > 0) { - if (cp->ppm_previous == 0) { - N_ppm = cio_read(cio, 4); /* N_ppm */ - len -= 4; - } else { - N_ppm = cp->ppm_previous; + // first PPM marker + if + (l_Z_ppm == 0) + { + if + (p_header_size < 4) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading PPM marker\n"); + return 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(p_manager, EVT_ERROR, "Not enough memory reading ppm marker\n"); + return false; } - j = cp->ppm_store; - if (Z_ppm == 0) { /* First PPM marker */ - cp->ppm_data = (unsigned char *) opj_malloc(N_ppm * sizeof(unsigned char)); - cp->ppm_data_first = cp->ppm_data; - cp->ppm_len = N_ppm; - } else { /* NON-first PPM marker */ - cp->ppm_data = (unsigned char *) opj_realloc(cp->ppm_data, (N_ppm + cp->ppm_store) * sizeof(unsigned char)); + memset(l_cp->ppm_buffer,0,l_cp->ppm_len); + } -#ifdef USE_JPWL - /* this memory allocation check could be done even in non-JPWL cases */ - if (cp->correct) { - if (!cp->ppm_data) { - opj_event_msg(j2k->cinfo, EVT_ERROR, - "JPWL: failed memory allocation during PPM marker parsing (pos. %x)\n", - cio_tell(cio)); - if (!JPWL_ASSUME || JPWL_ASSUME) { - opj_free(cp->ppm_data); - opj_event_msg(j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); - return; - } + while + (true) + { + 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(p_manager, EVT_ERROR, "Not enough memory reading ppm marker\n"); + return false; } + memset(l_cp->ppm_buffer+l_cp->ppm_data_size,0,l_N_ppm); + } + else + { + return false; } -#endif - - cp->ppm_data_first = cp->ppm_data; - cp->ppm_len = N_ppm + cp->ppm_store; - } - for (i = N_ppm; i > 0; i--) { /* Read packet header */ - cp->ppm_data[j] = cio_read(cio, 1); - j++; - len--; - if (len == 0) - break; /* Case of non-finished packet header in present marker but finished in next one */ - } - cp->ppm_previous = i - 1; - cp->ppm_store = j; - } -} - -static void j2k_read_ppt(opj_j2k_t *j2k) { - int len, Z_ppt, i, j = 0; - - opj_cp_t *cp = j2k->cp; - opj_tcp_t *tcp = cp->tcps + j2k->curtileno; - opj_cio_t *cio = j2k->cio; - - len = cio_read(cio, 2); - Z_ppt = cio_read(cio, 1); - tcp->ppt = 1; - if (Z_ppt == 0) { /* First PPT marker */ - tcp->ppt_data = (unsigned char *) opj_malloc((len - 3) * sizeof(unsigned char)); - tcp->ppt_data_first = tcp->ppt_data; - tcp->ppt_store = 0; - tcp->ppt_len = len - 3; - } else { /* NON-first PPT marker */ - tcp->ppt_data = (unsigned char *) opj_realloc(tcp->ppt_data, (len - 3 + tcp->ppt_store) * sizeof(unsigned char)); - tcp->ppt_data_first = tcp->ppt_data; - tcp->ppt_len = len - 3 + tcp->ppt_store; - } - j = tcp->ppt_store; - for (i = len - 3; i > 0; i--) { - tcp->ppt_data[j] = cio_read(cio, 1); - j++; - } - tcp->ppt_store = j; -} - -static void j2k_write_tlm(opj_j2k_t *j2k){ - int lenp; - opj_cio_t *cio = j2k->cio; - j2k->tlm_start = cio_tell(cio); - cio_write(cio, J2K_MS_TLM, 2);/* TLM */ - lenp = 4 + (5*j2k->totnum_tp); - cio_write(cio,lenp,2); /* Ltlm */ - cio_write(cio, 0,1); /* Ztlm=0*/ - cio_write(cio,80,1); /* Stlm ST=1(8bits-255 tiles max),SP=1(Ptlm=32bits) */ - cio_skip(cio,5*j2k->totnum_tp); -} - -static void j2k_write_sot(opj_j2k_t *j2k) { - int lenp, len; - - opj_cio_t *cio = j2k->cio; - - j2k->sot_start = cio_tell(cio); - cio_write(cio, J2K_MS_SOT, 2); /* SOT */ - lenp = cio_tell(cio); - cio_skip(cio, 2); /* Lsot (further) */ - cio_write(cio, j2k->curtileno, 2); /* Isot */ - cio_skip(cio, 4); /* Psot (further in j2k_write_sod) */ - cio_write(cio, j2k->cur_tp_num , 1); /* TPsot */ - cio_write(cio, j2k->cur_totnum_tp[j2k->curtileno], 1); /* TNsot */ - len = cio_tell(cio) - lenp; - cio_seek(cio, lenp); - cio_write(cio, len, 2); /* Lsot */ - cio_seek(cio, lenp + len); + } + 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 true; +} + +/** + * 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. +*/ +bool j2k_read_ppt ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ) +{ + + opj_cp_t *l_cp = 00; + opj_tcp_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(p_manager, EVT_ERROR, "Error reading PPT marker\n"); + return 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(p_manager, EVT_ERROR, "Not enough memory reading PPT marker\n"); + return 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(p_manager, EVT_ERROR, "Not enough memory reading PPT marker\n"); + return 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 true; +} +/** + * Writes the SOT marker (Start of tile-part) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_sot( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + const struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + opj_write_bytes(p_data,J2K_MS_SOT,2); /* SOT */ + p_data += 2; + + opj_write_bytes(p_data,10,2); /* Lsot */ + p_data += 2; + + opj_write_bytes(p_data, p_j2k->m_current_tile_number,2); /* Isot */ + p_data += 2; + + /* Psot */ + p_data += 4; + + opj_write_bytes(p_data, p_j2k->m_specific_param.m_encoder.m_current_tile_part_number,1); /* TPsot */ + ++p_data; + + opj_write_bytes(p_data, p_j2k->m_cp.tcps[p_j2k->m_current_tile_number].m_nb_tile_parts,1); /* TNsot */ + ++p_data; /* UniPG>> */ #ifdef USE_JPWL /* update markers struct */ - j2k_add_marker(j2k->cstr_info, J2K_MS_SOT, j2k->sot_start, len + 2); + j2k_add_marker(p_j2k->cstr_info, J2K_MS_SOT, p_j2k->sot_start, len + 2); #endif /* USE_JPWL */ - /* <<UniPG */ -} -static void j2k_read_sot(opj_j2k_t *j2k) { - int len, tileno, totlen, partno, numparts, i; - opj_tcp_t *tcp = NULL; - char status = 0; - - opj_cp_t *cp = j2k->cp; - opj_cio_t *cio = j2k->cio; + * p_data_written = 12; + return true; +} - len = cio_read(cio, 2); - tileno = cio_read(cio, 2); +/** + * 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. +*/ +bool j2k_read_sot ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ) +{ + + opj_cp_t *l_cp = 00; + opj_tcp_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(p_manager, EVT_ERROR, "Error reading SOT marker\n"); + return 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 (j2k->cp->correct) { + 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(j2k->cinfo, EVT_ERROR, + 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(j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + opj_event_msg(p_j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); return; } /* we try to correct */ tileno = backup_tileno; - opj_event_msg(j2k->cinfo, EVT_WARNING, "- trying to adjust this\n" + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- trying to adjust this\n" "- setting tile number to %d\n", tileno); } @@ -1309,38 +5902,28 @@ static void j2k_read_sot(opj_j2k_t *j2k) { }; #endif /* USE_JPWL */ - if (cp->tileno_size == 0) { - cp->tileno[cp->tileno_size] = tileno; - cp->tileno_size++; - } else { - i = 0; - while (i < cp->tileno_size && status == 0) { - status = cp->tileno[i] == tileno ? 1 : 0; - i++; - } - if (status == 0) { - cp->tileno[cp->tileno_size] = tileno; - cp->tileno_size++; - } - } - - totlen = cio_read(cio, 4); + /* 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 (j2k->cp->correct) { + if (p_j2k->m_cp->correct) { /* totlen is negative or larger than the bytes left!!! */ - if ((totlen < 0) || (totlen > (cio_numbytesleft(cio) + 8))) { - opj_event_msg(j2k->cinfo, EVT_ERROR, + 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, cio_numbytesleft(cio) + 8); + totlen, p_stream_numbytesleft(p_stream) + 8); if (!JPWL_ASSUME) { - opj_event_msg(j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + opj_event_msg(p_j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); return; } /* we try to correct */ totlen = 0; - opj_event_msg(j2k->cinfo, EVT_WARNING, "- trying to adjust this\n" + 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); } @@ -1348,316 +5931,866 @@ static void j2k_read_sot(opj_j2k_t *j2k) { }; #endif /* USE_JPWL */ - if (!totlen) - totlen = cio_numbytesleft(cio) + 8; - - partno = cio_read(cio, 1); - numparts = cio_read(cio, 1); + if + (!l_tot_len) + { + opj_event_msg(p_manager, EVT_ERROR, "Cannot read data with no size known, giving up\n"); + return false; + } + + opj_read_bytes(p_header_data,&l_current_part ,1); /* Psot */ + ++p_header_data; - j2k->curtileno = tileno; - j2k->cur_tp_num = partno; - j2k->eot = cio_getbp(cio) - 12 + totlen; - j2k->state = J2K_STATE_TPH; - tcp = &cp->tcps[j2k->curtileno]; + opj_read_bytes(p_header_data,&l_num_parts ,1); /* Psot */ + ++p_header_data; - /* Index */ - if (j2k->cstr_info) { - if (tcp->first) { - if (tileno == 0) - j2k->cstr_info->main_head_end = cio_tell(cio) - 13; - j2k->cstr_info->tile[tileno].tileno = tileno; - j2k->cstr_info->tile[tileno].start_pos = cio_tell(cio) - 12; - j2k->cstr_info->tile[tileno].end_pos = j2k->cstr_info->tile[tileno].start_pos + totlen - 1; - j2k->cstr_info->tile[tileno].num_tps = numparts; - if (numparts) - j2k->cstr_info->tile[tileno].tp = (opj_tp_info_t *) opj_malloc(numparts * sizeof(opj_tp_info_t)); - else - j2k->cstr_info->tile[tileno].tp = (opj_tp_info_t *) opj_malloc(10 * sizeof(opj_tp_info_t)); // Fixme (10) + 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; } - else { - j2k->cstr_info->tile[tileno].end_pos += totlen; - } - j2k->cstr_info->tile[tileno].tp[partno].tp_start_pos = cio_tell(cio) - 12; - j2k->cstr_info->tile[tileno].tp[partno].tp_end_pos = - j2k->cstr_info->tile[tileno].tp[partno].tp_start_pos + totlen - 1; } + p_j2k->m_specific_param.m_decoder.m_sot_length = l_tot_len - 12; + p_j2k->m_specific_param.m_decoder.m_state = 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 */ - if (tcp->first == 1) { - /* Initialization PPT */ - opj_tccp_t *tmp = tcp->tccps; - memcpy(tcp, j2k->default_tcp, sizeof(opj_tcp_t)); - tcp->ppt = 0; - tcp->ppt_data = NULL; - tcp->ppt_data_first = NULL; - tcp->tccps = tmp; - - for (i = 0; i < j2k->image->numcomps; i++) { - tcp->tccps[i] = j2k->default_tcp->tccps[i]; + /* 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) + } } - cp->tcps[j2k->curtileno].first = 0; - } + 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 true; } -static void j2k_write_sod(opj_j2k_t *j2k, void *tile_coder) { - int l, layno; - int totlen; - opj_tcp_t *tcp = NULL; - opj_codestream_info_t *cstr_info = NULL; - - opj_tcd_t *tcd = (opj_tcd_t*)tile_coder; /* cast is needed because of conflicts in header inclusions */ - opj_cp_t *cp = j2k->cp; - opj_cio_t *cio = j2k->cio; - - tcd->tp_num = j2k->tp_num ; - tcd->cur_tp_num = j2k->cur_tp_num; - - cio_write(cio, J2K_MS_SOD, 2); - if (j2k->curtileno == 0) { - j2k->sod_start = cio_tell(cio) + j2k->pos_correction; - } +/** + * Writes the SOD marker (Start of data) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_sod( + opj_j2k_t *p_j2k, + struct opj_tcd * p_tile_coder, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 p_total_data_size, + const struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + opj_tcp_t *l_tcp = 00; + opj_codestream_info_t *l_cstr_info = 00; + opj_cp_t *l_cp = 00; + + OPJ_UINT32 l_size_tile; + OPJ_UINT32 l_remaining_data; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + opj_write_bytes(p_data,J2K_MS_SOD,2); /* SOD */ + p_data += 2; + + /* make room for the EOF marker */ + l_remaining_data = p_total_data_size - 4; + + l_cp = &(p_j2k->m_cp); + l_tcp = &l_cp->tcps[p_j2k->m_current_tile_number]; + l_cstr_info = p_j2k->cstr_info; + + /* update tile coder */ + p_tile_coder->tp_num = p_j2k->m_specific_param.m_encoder.m_current_poc_tile_part_number ; + p_tile_coder->cur_tp_num = p_j2k->m_specific_param.m_encoder.m_current_tile_part_number; + l_size_tile = l_cp->th * l_cp->tw; /* INDEX >> */ - cstr_info = j2k->cstr_info; - if (cstr_info) { - if (!j2k->cur_tp_num ) { - cstr_info->tile[j2k->curtileno].end_header = cio_tell(cio) + j2k->pos_correction - 1; - j2k->cstr_info->tile[j2k->curtileno].tileno = j2k->curtileno; + if + (l_cstr_info) + { + if + (!p_j2k->m_specific_param.m_encoder.m_current_tile_part_number ) + { + //TODO cstr_info->tile[p_j2k->m_current_tile_number].end_header = p_stream_tell(p_stream) + p_j2k->pos_correction - 1; + l_cstr_info->tile[p_j2k->m_current_tile_number].tileno = p_j2k->m_current_tile_number; } - else{ - if(cstr_info->tile[j2k->curtileno].packet[cstr_info->packno - 1].end_pos < cio_tell(cio)) - cstr_info->tile[j2k->curtileno].packet[cstr_info->packno].start_pos = cio_tell(cio); + else + { + /* + TODO + if + (cstr_info->tile[p_j2k->m_current_tile_number].packet[cstr_info->packno - 1].end_pos < p_stream_tell(p_stream)) + { + cstr_info->tile[p_j2k->m_current_tile_number].packet[cstr_info->packno].start_pos = p_stream_tell(p_stream); + }*/ + } /* UniPG>> */ #ifdef USE_JPWL /* update markers struct */ - j2k_add_marker(j2k->cstr_info, J2K_MS_SOD, j2k->sod_start, 2); + j2k_add_marker(p_j2k->cstr_info, J2K_MS_SOD, p_j2k->sod_start, 2); #endif /* USE_JPWL */ /* <<UniPG */ } /* << INDEX */ - tcp = &cp->tcps[j2k->curtileno]; - for (layno = 0; layno < tcp->numlayers; layno++) { - if (tcp->rates[layno]>(j2k->sod_start / (cp->th * cp->tw))) { - tcp->rates[layno]-=(j2k->sod_start / (cp->th * cp->tw)); - } else if (tcp->rates[layno]) { - tcp->rates[layno]=1; + if + (p_j2k->m_specific_param.m_encoder.m_current_tile_part_number == 0) + { + p_tile_coder->tcd_image->tiles->packno = 0; + if + (l_cstr_info) + { + l_cstr_info->packno = 0; } } - if(j2k->cur_tp_num == 0){ - tcd->tcd_image->tiles->packno = 0; - if(cstr_info) - cstr_info->packno = 0; + *p_data_written = 0; + if + (! tcd_encode_tile(p_tile_coder, p_j2k->m_current_tile_number, p_data, p_data_written, l_remaining_data , l_cstr_info)) + { + opj_event_msg(p_manager, EVT_ERROR, "Cannot encode tile\n"); + return false; } - - l = tcd_encode_tile(tcd, j2k->curtileno, cio_getbp(cio), cio_numbytesleft(cio) - 2, cstr_info); - - /* Writing Psot in SOT marker */ - totlen = cio_tell(cio) + l - j2k->sot_start; - cio_seek(cio, j2k->sot_start + 6); - cio_write(cio, totlen, 4); - cio_seek(cio, j2k->sot_start + totlen); - /* Writing Ttlm and Ptlm in TLM marker */ - if(cp->cinema){ - cio_seek(cio, j2k->tlm_start + 6 + (5*j2k->cur_tp_num)); - cio_write(cio, j2k->curtileno, 1); - cio_write(cio, totlen, 4); - } - cio_seek(cio, j2k->sot_start + totlen); + *p_data_written += 2; + return true; } -static void j2k_read_sod(opj_j2k_t *j2k) { - int len, truncate = 0, i; - unsigned char *data = NULL, *data_ptr = NULL; +/** + * Updates the Tile Length Marker. + */ +void j2k_update_tlm ( + opj_j2k_t * p_j2k, + OPJ_UINT32 p_tile_part_size + ) +{ + opj_write_bytes(p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current,p_j2k->m_current_tile_number,1); /* PSOT */ + ++p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current; + opj_write_bytes(p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current,p_tile_part_size,4); /* PSOT */ + p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current += 4; +} - opj_cio_t *cio = j2k->cio; - int curtileno = j2k->curtileno; + +/** + * 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. +*/ +bool j2k_read_sod ( + opj_j2k_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_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*) my_opj_malloc(p_j2k->m_specific_param.m_decoder.m_sot_length); + } + else + { + *l_current_data = (OPJ_BYTE*) 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(p_manager, EVT_ERROR, "Cannot decode tile\n"); + return false; + } /* Index */ - if (j2k->cstr_info) { - j2k->cstr_info->tile[j2k->curtileno].tp[j2k->cur_tp_num].tp_end_header = - cio_tell(cio) + j2k->pos_correction - 1; - if (j2k->cur_tp_num == 0) - j2k->cstr_info->tile[j2k->curtileno].end_header = cio_tell(cio) + j2k->pos_correction - 1; - j2k->cstr_info->packno = 0; + 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; } - - len = int_min(j2k->eot - cio_getbp(cio), cio_numbytesleft(cio) + 1); + 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_DEC_STATE_NEOC; + } + else + { + p_j2k->m_specific_param.m_decoder.m_state = J2K_DEC_STATE_TPHSOT; + } + *l_tile_len += l_current_read_size; + return true; +} - if (len == cio_numbytesleft(cio) + 1) { - truncate = 1; /* Case of a truncate codestream */ - } +/** + * Writes the EOC marker (End of Codestream) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_eoc( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + opj_write_bytes(p_j2k->m_specific_param.m_encoder.m_header_tile_data,J2K_MS_EOC,2); /* EOC */ + - data = j2k->tile_data[curtileno]; - data = (unsigned char*) opj_realloc(data, (j2k->tile_len[curtileno] + len) * sizeof(unsigned char)); +/* UniPG>> */ +#ifdef USE_JPWL + /* update markers struct */ + j2k_add_marker(p_j2k->cstr_info, J2K_MS_EOC, p_stream_tell(p_stream) - 2, 2); +#endif /* USE_JPWL */ - data_ptr = data + j2k->tile_len[curtileno]; - for (i = 0; i < len; i++) { - data_ptr[i] = cio_read(cio, 1); + if + (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,2,p_manager) != 2) + { + return false; } + if + (! opj_stream_flush(p_stream,p_manager)) + { + return false; + } + return true; +} - j2k->tile_len[curtileno] += len; - j2k->tile_data[curtileno] = data; - - if (!truncate) { - j2k->state = J2K_STATE_TPHSOT; - } else { - j2k->state = J2K_STATE_NEOC; /* RAJOUTE !! */ + +/** + * Inits the Info + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_init_info( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + opj_codestream_info_t * l_cstr_info = 00; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + l_cstr_info = p_j2k->cstr_info; + + if + (l_cstr_info) + { + OPJ_UINT32 compno; + l_cstr_info->tile = (opj_tile_info_t *) opj_malloc(p_j2k->m_cp.tw * p_j2k->m_cp.th * sizeof(opj_tile_info_t)); + l_cstr_info->image_w = p_j2k->m_image->x1 - p_j2k->m_image->x0; + l_cstr_info->image_h = p_j2k->m_image->y1 - p_j2k->m_image->y0; + l_cstr_info->prog = (&p_j2k->m_cp.tcps[0])->prg; + l_cstr_info->tw = p_j2k->m_cp.tw; + l_cstr_info->th = p_j2k->m_cp.th; + l_cstr_info->tile_x = p_j2k->m_cp.tdx; /* new version parser */ + l_cstr_info->tile_y = p_j2k->m_cp.tdy; /* new version parser */ + l_cstr_info->tile_Ox = p_j2k->m_cp.tx0; /* new version parser */ + l_cstr_info->tile_Oy = p_j2k->m_cp.ty0; /* new version parser */ + l_cstr_info->numcomps = p_j2k->m_image->numcomps; + l_cstr_info->numlayers = (&p_j2k->m_cp.tcps[0])->numlayers; + l_cstr_info->numdecompos = (OPJ_INT32*) opj_malloc(p_j2k->m_image->numcomps * sizeof(OPJ_INT32)); + for (compno=0; compno < p_j2k->m_image->numcomps; compno++) { + l_cstr_info->numdecompos[compno] = (&p_j2k->m_cp.tcps[0])->tccps->numresolutions - 1; + } + l_cstr_info->D_max = 0.0; /* ADD Marcela */ + l_cstr_info->main_head_start = opj_stream_tell(p_stream); /* position of SOC */ + l_cstr_info->maxmarknum = 100; + l_cstr_info->marker = (opj_marker_info_t *) opj_malloc(l_cstr_info->maxmarknum * sizeof(opj_marker_info_t)); + l_cstr_info->marknum = 0; } - j2k->cur_tp_num++; + return j2k_calculate_tp(p_j2k,&(p_j2k->m_cp),&p_j2k->m_specific_param.m_encoder.m_total_tile_parts,p_j2k->m_image,p_manager); } -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]; - opj_cio_t *cio = j2k->cio; - int numcomps = j2k->image->numcomps; +/** + * Creates a tile-coder decoder. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_create_tcd( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); - cio_write(cio, J2K_MS_RGN, 2); /* RGN */ - cio_write(cio, numcomps <= 256 ? 5 : 6, 2); /* Lrgn */ - cio_write(cio, compno, numcomps <= 256 ? 1 : 2); /* Crgn */ - cio_write(cio, 0, 1); /* Srgn */ - cio_write(cio, tcp->tccps[compno].roishift, 1); /* SPrgn */ + p_j2k->m_tcd = tcd_create(false); + if + (! p_j2k->m_tcd) + { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to create Tile Coder\n"); + return false; + } + if + (! tcd_init(p_j2k->m_tcd,p_j2k->m_image,&p_j2k->m_cp)) + { + tcd_destroy(p_j2k->m_tcd); + p_j2k->m_tcd = 00; + return false; + } + return true; } -static void j2k_read_rgn(opj_j2k_t *j2k) { - int len, compno, roisty; +OPJ_FLOAT32 get_tp_stride (opj_tcp_t * p_tcp) +{ + return (OPJ_FLOAT32) ((p_tcp->m_nb_tile_parts - 1) * 14); +} - opj_cp_t *cp = j2k->cp; - opj_tcp_t *tcp = j2k->state == J2K_STATE_TPH ? &cp->tcps[j2k->curtileno] : j2k->default_tcp; - opj_cio_t *cio = j2k->cio; - int numcomps = j2k->image->numcomps; +OPJ_FLOAT32 get_default_stride (opj_tcp_t * p_tcp) +{ + return 0; +} - len = cio_read(cio, 2); /* Lrgn */ - compno = cio_read(cio, numcomps <= 256 ? 1 : 2); /* Crgn */ - roisty = cio_read(cio, 1); /* Srgn */ +/** + * Updates the rates of the tcp. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_update_rates( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + opj_cp_t * l_cp = 00; + opj_image_t * l_image = 00; + opj_tcp_t * l_tcp = 00; + opj_image_comp_t * l_img_comp = 00; + + OPJ_UINT32 i,j,k; + OPJ_INT32 l_x0,l_y0,l_x1,l_y1; + OPJ_FLOAT32 * l_rates = 0; + OPJ_FLOAT32 l_sot_remove; + OPJ_UINT32 l_bits_empty, l_size_pixel; + OPJ_UINT32 l_tile_size = 0; + OPJ_UINT32 l_last_res; + OPJ_FLOAT32 (* l_tp_stride_func)(opj_tcp_t *) = 00; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + + l_cp = &(p_j2k->m_cp); + l_image = p_j2k->m_image; + l_tcp = l_cp->tcps; + + l_bits_empty = 8 * l_image->comps->dx * l_image->comps->dy; + l_size_pixel = l_image->numcomps * l_image->comps->prec; + l_sot_remove = ((OPJ_FLOAT32) opj_stream_tell(p_stream)) / (l_cp->th * l_cp->tw); + + if + (l_cp->m_specific_param.m_enc.m_tp_on) + { + l_tp_stride_func = get_tp_stride; + } + else + { + l_tp_stride_func = get_default_stride; + } -#ifdef USE_JPWL - if (j2k->cp->correct) { - /* totlen is negative or larger than the bytes left!!! */ - if (compno >= numcomps) { - opj_event_msg(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(j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); - return; + for + (i=0;i<l_cp->th;++i) + { + for + (j=0;j<l_cp->tw;++j) + { + OPJ_FLOAT32 l_offset = ((*l_tp_stride_func)(l_tcp)) / l_tcp->numlayers; + /* 4 borders of the tile rescale on the image if necessary */ + l_x0 = int_max(l_cp->tx0 + j * l_cp->tdx, l_image->x0); + l_y0 = int_max(l_cp->ty0 + i * l_cp->tdy, l_image->y0); + l_x1 = int_min(l_cp->tx0 + (j + 1) * l_cp->tdx, l_image->x1); + l_y1 = int_min(l_cp->ty0 + (i + 1) * l_cp->tdy, l_image->y1); + l_rates = l_tcp->rates; + + /* Modification of the RATE >> */ + if + (*l_rates) + { + *l_rates = (( (float) (l_size_pixel * (l_x1 - l_x0) * (l_y1 - l_y0))) + / + ((*l_rates) * l_bits_empty) + ) + - + l_offset; + } + ++l_rates; + for + (k = 1; k < l_tcp->numlayers; ++k) + { + if + (*l_rates) + { + *l_rates = (( (OPJ_FLOAT32) (l_size_pixel * (l_x1 - l_x0) * (l_y1 - l_y0))) + / + ((*l_rates) * l_bits_empty) + ) + - + l_offset; + } + ++l_rates; } + ++l_tcp; } - }; -#endif /* USE_JPWL */ - - tcp->tccps[compno].roishift = cio_read(cio, 1); /* SPrgn */ + } + + l_tcp = l_cp->tcps; + for + (i=0;i<l_cp->th;++i) + { + for + (j=0;j<l_cp->tw;++j) + { + l_rates = l_tcp->rates; + if + (*l_rates) + { + *l_rates -= l_sot_remove; + if + (*l_rates < 30) + { + *l_rates = 30; + } + } + ++l_rates; + l_last_res = l_tcp->numlayers - 1; + for + (k = 1; k < l_last_res; ++k) + { + if + (*l_rates) + { + *l_rates -= l_sot_remove; + if + (*l_rates < *(l_rates - 1) + 10) + { + *l_rates = (*(l_rates - 1)) + 20; + } + } + ++l_rates; + } + if + (*l_rates) + { + *l_rates -= (l_sot_remove + 2.f); + if + (*l_rates < *(l_rates - 1) + 10) + { + *l_rates = (*(l_rates - 1)) + 20; + } + } + ++l_tcp; + } + } + + l_img_comp = l_image->comps; + l_tile_size = 0; + for + (i=0;i<l_image->numcomps;++i) + { + l_tile_size += ( uint_ceildiv(l_cp->tdx,l_img_comp->dx) + * + uint_ceildiv(l_cp->tdy,l_img_comp->dy) + * + l_img_comp->prec + ); + ++l_img_comp; + } + + l_tile_size = (OPJ_UINT32) (l_tile_size * 0.1625); /* 1.3/8 = 0.1625 */ + l_tile_size += j2k_get_specific_header_sizes(p_j2k); + + p_j2k->m_specific_param.m_encoder.m_encoded_tile_size = l_tile_size; + p_j2k->m_specific_param.m_encoder.m_encoded_tile_data = (OPJ_BYTE *) my_opj_malloc(p_j2k->m_specific_param.m_encoder.m_encoded_tile_size); + if + (p_j2k->m_specific_param.m_encoder.m_encoded_tile_data == 00) + { + return false; + } + if + (l_cp->m_specific_param.m_enc.m_cinema) + { + p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer = (OPJ_BYTE *) opj_malloc(5*p_j2k->m_specific_param.m_encoder.m_total_tile_parts); + if + (! p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer) + { + return false; + } + p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current = p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer; + } + return true; } -static void j2k_write_eoc(opj_j2k_t *j2k) { - opj_cio_t *cio = j2k->cio; - /* opj_event_msg(j2k->cinfo, "%.8x: EOC\n", cio_tell(cio) + j2k->pos_correction); */ - cio_write(cio, J2K_MS_EOC, 2); +/** + * Reads a EOC marker (End Of Codestream) + * + * @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. +*/ +bool j2k_read_eoc ( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 i; + opj_tcd_t * l_tcd = 00; + OPJ_UINT32 l_nb_tiles; + opj_tcp_t * l_tcp = 00; + bool l_success; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_nb_tiles = p_j2k->m_cp.th * p_j2k->m_cp.tw; + l_tcp = p_j2k->m_cp.tcps; + + l_tcd = tcd_create(true); + if + (l_tcd == 00) + { + opj_event_msg(p_manager, EVT_ERROR, "Cannot decode tile, memory error\n"); + return false; + } -/* UniPG>> */ -#ifdef USE_JPWL - /* update markers struct */ - j2k_add_marker(j2k->cstr_info, J2K_MS_EOC, cio_tell(cio) - 2, 2); -#endif /* USE_JPWL */ -/* <<UniPG */ -} + -static void j2k_read_eoc(opj_j2k_t *j2k) { - int i, tileno; - bool success; - - /* if packets should be decoded */ - if (j2k->cp->limit_decoding != DECODE_ALL_BUT_PACKETS) { - opj_tcd_t *tcd = tcd_create(j2k->cinfo); - tcd_malloc_decode(tcd, j2k->image, j2k->cp); - for (i = 0; i < j2k->cp->tileno_size; i++) { - tcd_malloc_decode_tile(tcd, j2k->image, j2k->cp, i, j2k->cstr_info); - tileno = j2k->cp->tileno[i]; - success = tcd_decode_tile(tcd, j2k->tile_data[tileno], j2k->tile_len[tileno], tileno, j2k->cstr_info); - opj_free(j2k->tile_data[tileno]); - j2k->tile_data[tileno] = NULL; - tcd_free_decode_tile(tcd, i); - if (success == false) { - j2k->state |= J2K_STATE_ERR; + for + (i = 0; i < l_nb_tiles; ++i) + { + if + (l_tcp->m_data) + { + if + (! tcd_init_decode_tile(l_tcd, i)) + { + tcd_destroy(l_tcd); + opj_event_msg(p_manager, EVT_ERROR, "Cannot decode tile, memory error\n"); + return false; + } + l_success = tcd_decode_tile(l_tcd, l_tcp->m_data, l_tcp->m_data_size, i, p_j2k->cstr_info); + /* cleanup */ + if + (! l_success) + { + p_j2k->m_specific_param.m_decoder.m_state |= J2K_DEC_STATE_ERR; break; } } - tcd_free_decode(tcd); - tcd_destroy(tcd); + j2k_tcp_destroy(l_tcp); + ++l_tcp; } - /* if packets should not be decoded */ - else { - for (i = 0; i < j2k->cp->tileno_size; i++) { - tileno = j2k->cp->tileno[i]; - opj_free(j2k->tile_data[tileno]); - j2k->tile_data[tileno] = NULL; + tcd_destroy(l_tcd); + return true; +} + +/** + * Writes the image components. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_image_components( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 compno; + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + for + (compno = 1; compno < p_j2k->m_image->numcomps; ++compno) + { + if + (! j2k_write_coc(p_j2k,compno,p_stream, p_manager)) + { + return false; } - } - if (j2k->state & J2K_STATE_ERR) - j2k->state = J2K_STATE_MT + J2K_STATE_ERR; - else - j2k->state = J2K_STATE_MT; + if + (! j2k_write_qcc(p_j2k,compno,p_stream, p_manager)) + { + return false; + } + } + return true; } -typedef struct opj_dec_mstabent { - /** marker value */ - int id; - /** value of the state when the marker can appear */ - int states; - /** action linked to the marker */ - void (*handler) (opj_j2k_t *j2k); -} opj_dec_mstabent_t; - -opj_dec_mstabent_t j2k_dec_mstab[] = { - {J2K_MS_SOC, J2K_STATE_MHSOC, j2k_read_soc}, - {J2K_MS_SOT, J2K_STATE_MH | J2K_STATE_TPHSOT, j2k_read_sot}, - {J2K_MS_SOD, J2K_STATE_TPH, j2k_read_sod}, - {J2K_MS_EOC, J2K_STATE_TPHSOT, j2k_read_eoc}, - {J2K_MS_SIZ, J2K_STATE_MHSIZ, j2k_read_siz}, - {J2K_MS_COD, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_cod}, - {J2K_MS_COC, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_coc}, - {J2K_MS_RGN, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_rgn}, - {J2K_MS_QCD, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_qcd}, - {J2K_MS_QCC, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_qcc}, - {J2K_MS_POC, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_poc}, - {J2K_MS_TLM, J2K_STATE_MH, j2k_read_tlm}, - {J2K_MS_PLM, J2K_STATE_MH, j2k_read_plm}, - {J2K_MS_PLT, J2K_STATE_TPH, j2k_read_plt}, - {J2K_MS_PPM, J2K_STATE_MH, j2k_read_ppm}, - {J2K_MS_PPT, J2K_STATE_TPH, j2k_read_ppt}, - {J2K_MS_SOP, 0, 0}, - {J2K_MS_CRG, J2K_STATE_MH, j2k_read_crg}, - {J2K_MS_COM, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_com}, +/** + * Writes regions of interests. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_regions( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 compno; + const opj_tccp_t *l_tccp = 00; + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_tccp = p_j2k->m_cp.tcps->tccps; + for + (compno = 0; compno < p_j2k->m_image->numcomps; ++compno) + { + if + (l_tccp->roishift) + { + if + (! j2k_write_rgn(p_j2k,0,compno,p_stream,p_manager)) + { + return false; + } + } + ++l_tccp; + } + return true; +} +/** + * Writes the updated tlm. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_updated_tlm( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 l_tlm_size; + OPJ_SIZE_T l_tlm_position, l_current_position; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_tlm_size = 5 * p_j2k->m_specific_param.m_encoder.m_total_tile_parts; + l_tlm_position = 6 + p_j2k->m_specific_param.m_encoder.m_tlm_start; + l_current_position = opj_stream_tell(p_stream); + + if + (! opj_stream_seek(p_stream,l_tlm_position,p_manager)) + { + return false; + } + if + (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer,l_tlm_size,p_manager) != l_tlm_size) + { + return false; + } + if + (! opj_stream_seek(p_stream,l_current_position,p_manager)) + { + return false; + } + return true; +} -#ifdef USE_JPWL - {J2K_MS_EPC, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_epc}, - {J2K_MS_EPB, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_epb}, - {J2K_MS_ESD, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_esd}, - {J2K_MS_RED, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_red}, -#endif /* USE_JPWL */ -#ifdef USE_JPSEC - {J2K_MS_SEC, J2K_STATE_MH, j2k_read_sec}, - {J2K_MS_INSEC, 0, j2k_read_insec}, -#endif /* USE_JPSEC */ +/** + * Ends the encoding, i.e. frees memory. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_end_encoding( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + tcd_destroy(p_j2k->m_tcd); + p_j2k->m_tcd = 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 = 0; + p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current = 0; + } + if + (p_j2k->m_specific_param.m_encoder.m_encoded_tile_data) + { + opj_free(p_j2k->m_specific_param.m_encoder.m_encoded_tile_data); + p_j2k->m_specific_param.m_encoder.m_encoded_tile_data = 0; + } + p_j2k->m_specific_param.m_encoder.m_encoded_tile_size = 0; - {0, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_unk} -}; + return true; +} + +/** + * Gets the offset of the header. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_get_end_header( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + p_j2k->cstr_info->main_head_end = opj_stream_tell(p_stream); + return true; +} -static void j2k_read_unk(opj_j2k_t *j2k) { - opj_event_msg(j2k->cinfo, EVT_WARNING, "Unknown marker\n"); + + +/** + * Reads an unknown marker + * + * @param p_stream the stream object to read from. + * @param p_j2k the jpeg2000 codec. + * @param p_manager the user event manager. + * + * @return true if the marker could be deduced. +*/ +bool j2k_read_unk ( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_BYTE l_data [2]; + OPJ_UINT32 l_unknown_size; + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + opj_event_msg(p_manager, EVT_WARNING, "Unknown marker\n"); + #ifdef USE_JPWL - if (j2k->cp->correct) { - int m = 0, id, i; - int min_id = 0, min_dist = 17, cur_dist = 0, tmp_id; - cio_seek(j2k->cio, cio_tell(j2k->cio) - 2); - id = cio_read(j2k->cio, 2); - opj_event_msg(j2k->cinfo, EVT_ERROR, + if (p_j2k->m_cp->correct) { + OPJ_INT32 m = 0, id, i; + OPJ_INT32 min_id = 0, min_dist = 17, cur_dist = 0, tmp_id; + p_stream_seek(p_j2k->p_stream, p_stream_tell(p_j2k->p_stream) - 2); + id = p_stream_read(p_j2k->p_stream, 2); + opj_event_msg(p_j2k->cinfo, EVT_ERROR, "JPWL: really don't know this marker %x\n", id); if (!JPWL_ASSUME) { - opj_event_msg(j2k->cinfo, EVT_ERROR, + opj_event_msg(p_j2k->cinfo, EVT_ERROR, "- possible synch loss due to uncorrectable codestream errors => giving up\n"); return; } @@ -1688,358 +6821,940 @@ static void j2k_read_unk(opj_j2k_t *j2k) { /* do we substitute the marker? */ if (min_dist < JPWL_MAXIMUM_HAMMING) { - opj_event_msg(j2k->cinfo, EVT_ERROR, + opj_event_msg(p_j2k->cinfo, EVT_ERROR, "- marker %x is at distance %d from the read %x\n", min_id, min_dist, id); - opj_event_msg(j2k->cinfo, EVT_ERROR, + opj_event_msg(p_j2k->cinfo, EVT_ERROR, "- trying to substitute in place and crossing fingers!\n"); - cio_seek(j2k->cio, cio_tell(j2k->cio) - 2); - cio_write(j2k->cio, min_id, 2); + p_stream_seek(p_j2k->p_stream, p_stream_tell(p_j2k->p_stream) - 2); + p_stream_write(p_j2k->p_stream, min_id, 2); /* rewind */ - cio_seek(j2k->cio, cio_tell(j2k->cio) - 2); + p_stream_seek(p_j2k->p_stream, p_stream_tell(p_j2k->p_stream) - 2); } }; #endif /* USE_JPWL */ + if + (opj_stream_read_data(p_stream,l_data,2,p_manager) != 2) + { + opj_event_msg(p_manager, EVT_WARNING, "Unknown marker\n"); + return false; + } + opj_read_bytes(l_data,&l_unknown_size,2); + if + (l_unknown_size < 2) + { + return false; + } + l_unknown_size-=2; + if + (opj_stream_skip(p_stream,l_unknown_size,p_manager) != l_unknown_size) + { + return false; + } + return true; } /** -Read the lookup table containing all the marker, status and action -@param id Marker value + * 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 opj_dec_mstabent_t *j2k_dec_mstab_lookup(int id) { - opj_dec_mstabent_t *e; - for (e = j2k_dec_mstab; e->id != 0; e++) { - if (e->id == id) { +const opj_dec_memory_marker_handler_t * j2k_get_marker_handler (OPJ_UINT32 p_id) +{ + const opj_dec_memory_marker_handler_t *e; + for + (e = j2k_memory_marker_handler_tab; e->id != 0; ++e) + { + if + (e->id == p_id) + { break; } } return e; } +/** + * Destroys a tile coding parameter structure. + * + * @param p_tcp the tile coding parameter to destroy. + */ +void j2k_tcp_destroy (opj_tcp_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;i<p_tcp->m_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_t *p_cp) +{ + OPJ_UINT32 l_nb_tiles; + opj_tcp_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; + } + } +} + /* ----------------------------------------------------------------------- */ /* J2K / JPT decoder interface */ /* ----------------------------------------------------------------------- */ +/** + * Creates a J2K decompression structure. + * + * @return a handle to a J2K decompressor if successful, NULL otherwise. +*/ +opj_j2k_t* j2k_create_decompress() +{ + opj_j2k_t *l_j2k = (opj_j2k_t*) opj_malloc(sizeof(opj_j2k_t)); + if + (!l_j2k) + { + return 00; + } + memset(l_j2k,0,sizeof(opj_j2k_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_t*) opj_malloc(sizeof(opj_tcp_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_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; + } -opj_j2k_t* j2k_create_decompress(opj_common_ptr cinfo) { - opj_j2k_t *j2k = (opj_j2k_t*) opj_calloc(1, sizeof(opj_j2k_t)); - if(!j2k) - return NULL; - - j2k->default_tcp = (opj_tcp_t*) opj_calloc(1, sizeof(opj_tcp_t)); - if(!j2k->default_tcp) { - opj_free(j2k); - return NULL; + // execution list creation + l_j2k->m_procedure_list = opj_procedure_list_create(); + if + (! l_j2k->m_procedure_list) + { + j2k_destroy(l_j2k); + return 00; } + return l_j2k; +} - j2k->cinfo = cinfo; - j2k->tile_data = NULL; +opj_j2k_t* j2k_create_compress() +{ + opj_j2k_t *l_j2k = (opj_j2k_t*) opj_malloc(sizeof(opj_j2k_t)); + if + (!l_j2k) + { + return 00; + } + memset(l_j2k,0,sizeof(opj_j2k_t)); + l_j2k->m_is_decoder = 0; + l_j2k->m_cp.m_is_decoder = 0; + + l_j2k->m_specific_param.m_encoder.m_header_tile_data = (OPJ_BYTE *) opj_malloc(J2K_DEFAULT_HEADER_SIZE); + if + (! l_j2k->m_specific_param.m_encoder.m_header_tile_data) + { + j2k_destroy(l_j2k); + return 00; + } + l_j2k->m_specific_param.m_encoder.m_header_tile_data_size = J2K_DEFAULT_HEADER_SIZE; + + // validation list creation + l_j2k->m_validation_list = opj_procedure_list_create(); + if + (! l_j2k->m_validation_list) + { + j2k_destroy(l_j2k); + return 00; + } - return j2k; + // 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; } -void j2k_destroy_decompress(opj_j2k_t *j2k) { - int i = 0; - if(j2k->tile_len != NULL) { - opj_free(j2k->tile_len); - } - if(j2k->tile_data != NULL) { - opj_free(j2k->tile_data); +/** + * Destroys a jpeg2000 codec. + * + * @param p_j2k the jpeg20000 structure to destroy. + */ +void j2k_destroy (opj_j2k_t *p_j2k) +{ + if + (p_j2k == 00) + { + return; } - if(j2k->default_tcp != NULL) { - opj_tcp_t *default_tcp = j2k->default_tcp; - if(default_tcp->ppt_data_first != NULL) { - opj_free(default_tcp->ppt_data_first); + + if + (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(j2k->default_tcp->tccps != NULL) { - opj_free(j2k->default_tcp->tccps); + 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; } - opj_free(j2k->default_tcp); + } - if(j2k->cp != NULL) { - opj_cp_t *cp = j2k->cp; - if(cp->tcps != NULL) { - for(i = 0; i < cp->tw * cp->th; i++) { - if(cp->tcps[i].ppt_data_first != NULL) { - opj_free(cp->tcps[i].ppt_data_first); - } - if(cp->tcps[i].tccps != NULL) { - opj_free(cp->tcps[i].tccps); - } - } - opj_free(cp->tcps); - } - if(cp->ppm_data_first != NULL) { - opj_free(cp->ppm_data_first); + 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(cp->tileno != NULL) { - opj_free(cp->tileno); + 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(cp->comment != NULL) { - opj_free(cp->comment); + 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; } - - opj_free(cp); } - opj_free(j2k); + tcd_destroy(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); } -void j2k_setup_decoder(opj_j2k_t *j2k, opj_dparameters_t *parameters) { - if(j2k && parameters) { - /* create and initialize the coding parameters structure */ - opj_cp_t *cp = (opj_cp_t*) opj_calloc(1, sizeof(opj_cp_t)); - cp->reduce = parameters->cp_reduce; - cp->layer = parameters->cp_layer; - cp->limit_decoding = parameters->cp_limit_decoding; +/** + * Starts a compression scheme, i.e. validates the codec parameters, writes the header. + * + * @param p_j2k the jpeg2000 codec. + * @param p_stream the stream object. + * @param p_manager the user event manager. + * + * @return true if the codec is valid. + */ +bool j2k_start_compress( + opj_j2k_t *p_j2k, + opj_stream_private_t *p_stream, + opj_image_t * p_image, + opj_event_mgr_t * p_manager) +{ + // preconditions + assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); + p_j2k->m_image = p_image; + -#ifdef USE_JPWL - cp->correct = parameters->jpwl_correct; - cp->exp_comps = parameters->jpwl_exp_comps; - cp->max_tiles = parameters->jpwl_max_tiles; -#endif /* USE_JPWL */ + /* customization of the validation */ + j2k_setup_encoding_validation (p_j2k); + + /* validation of the parameters codec */ + if + (! j2k_exec(p_j2k,p_j2k->m_validation_list,p_stream,p_manager)) + { + return false; + } + /* customization of the encoding */ + j2k_setup_header_writting(p_j2k); - /* keep a link to cp so that we can destroy it later in j2k_destroy_decompress */ - j2k->cp = cp; + /* write header */ + if + (! j2k_exec (p_j2k,p_j2k->m_procedure_list,p_stream,p_manager)) + { + return false; } + return 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_t *p_j2k) +{ + // preconditions + assert(p_j2k != 00); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,j2k_read_header_procedure); -opj_image_t* j2k_decode(opj_j2k_t *j2k, opj_cio_t *cio, opj_codestream_info_t *cstr_info) { - opj_image_t *image = NULL; + /* DEVELOPER CORNER, add your custom procedures */ + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,j2k_copy_default_tcp_and_create_tcd); - opj_common_ptr cinfo = j2k->cinfo; +} - j2k->cio = cio; - j2k->cstr_info = cstr_info; - if (cstr_info) - memset(cstr_info, 0, sizeof(opj_codestream_info_t)); +/** + * Sets up the procedures to do on decoding data. Developpers wanting to extend the library can add their own reading procedures. + */ +void j2k_setup_decoding (opj_j2k_t *p_j2k) +{ + // preconditions + assert(p_j2k != 00); - /* create an empty image */ - image = opj_image_create0(); - j2k->image = image; + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,j2k_decode_tiles); + /* DEVELOPER CORNER, add your custom procedures */ - j2k->state = J2K_STATE_MHSOC; +} - for (;;) { - opj_dec_mstabent_t *e; - int id = cio_read(cio, 2); +/** + * Sets up the procedures to do on writting header. Developpers wanting to extend the library can add their own writting procedures. + */ +void j2k_setup_header_writting (opj_j2k_t *p_j2k) +{ + // preconditions + assert(p_j2k != 00); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,j2k_init_info ); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,j2k_write_soc ); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,j2k_write_siz ); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,j2k_write_cod ); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,j2k_write_qcd ); + -#ifdef USE_JPWL - /* we try to honor JPWL correction power */ - if (j2k->cp->correct) { + if + (p_j2k->m_cp.m_specific_param.m_enc.m_cinema) + { + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,j2k_write_image_components ); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,j2k_write_tlm ); + if + (p_j2k->m_cp.m_specific_param.m_enc.m_cinema == CINEMA4K_24) + { + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,j2k_write_poc ); + } + } + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,j2k_write_regions); - int orig_pos = cio_tell(cio); - bool status; + if + (p_j2k->m_cp.comment != 00) + { + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,j2k_write_com); + } + + /* DEVELOPER CORNER, insert your custom procedures */ + if + (p_j2k->m_cp.rsiz & MCT) + { + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,j2k_write_mct_data_group ); + } + /* End of Developer Corner */ - /* call the corrector */ - status = jpwl_correct(j2k); + if + (p_j2k->cstr_info) + { + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,j2k_get_end_header ); + } + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,j2k_create_tcd); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,j2k_update_rates); +} - /* go back to where you were */ - cio_seek(cio, orig_pos - 2); +/** + * 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_end_compress (opj_j2k_t *p_j2k) +{ + // preconditions + assert(p_j2k != 00); + + /* DEVELOPER CORNER, insert your custom procedures */ + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,j2k_write_eoc ); + if + (p_j2k->m_cp.m_specific_param.m_enc.m_cinema) + { + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,j2k_write_updated_tlm); + } + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,j2k_write_epc ); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,j2k_end_encoding ); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,j2k_destroy_header_memory); +} - /* re-read the marker */ - id = cio_read(cio, 2); - /* check whether it begins with ff */ - if (id >> 8 != 0xff) { - opj_event_msg(cinfo, EVT_ERROR, - "JPWL: possible bad marker %x at %d\n", - id, cio_tell(cio) - 2); - if (!JPWL_ASSUME) { - opj_image_destroy(image); - opj_event_msg(cinfo, EVT_ERROR, "JPWL: giving up\n"); - return 0; - } - /* we try to correct */ - id = id | 0xff00; - cio_seek(cio, cio_tell(cio) - 2); - cio_write(cio, id, 2); - opj_event_msg(cinfo, EVT_WARNING, "- trying to adjust this\n" - "- setting marker to %x\n", - id); - } - } -#endif /* USE_JPWL */ +/** + * 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_encoding_validation (opj_j2k_t *p_j2k) +{ + // preconditions + assert(p_j2k != 00); + opj_procedure_list_add_procedure(p_j2k->m_validation_list, j2k_build_encoder); + opj_procedure_list_add_procedure(p_j2k->m_validation_list, j2k_encoding_validation); - if (id >> 8 != 0xff) { - opj_image_destroy(image); - opj_event_msg(cinfo, EVT_ERROR, "%.8x: expected a marker instead of %x\n", cio_tell(cio) - 2, id); - return 0; - } - e = j2k_dec_mstab_lookup(id); - // Check if the marker is known - if (!(j2k->state & e->states)) { - opj_image_destroy(image); - opj_event_msg(cinfo, EVT_ERROR, "%.8x: unexpected marker %x\n", cio_tell(cio) - 2, id); - return 0; - } - // Check if the decoding is limited to the main header - if (e->id == J2K_MS_SOT && j2k->cp->limit_decoding == LIMIT_TO_MAIN_HEADER) { - opj_event_msg(cinfo, EVT_INFO, "Main Header decoded.\n"); - return image; - } - if (e->handler) { - (*e->handler)(j2k); - } - if (j2k->state & J2K_STATE_ERR) - return NULL; - - if (j2k->state == J2K_STATE_MT) { - break; - } - if (j2k->state == J2K_STATE_NEOC) { - break; - } - } - if (j2k->state == J2K_STATE_NEOC) { - j2k_read_eoc(j2k); - } + /* DEVELOPER CORNER, add your custom validation procedure */ + opj_procedure_list_add_procedure(p_j2k->m_validation_list, j2k_mct_validation); +} - if (j2k->state != J2K_STATE_MT) { - opj_event_msg(cinfo, EVT_WARNING, "Incomplete bitstream\n"); - } +/** + * 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_t *p_j2k) +{ + // preconditions + assert(p_j2k != 00); + opj_procedure_list_add_procedure(p_j2k->m_validation_list, j2k_build_decoder); + opj_procedure_list_add_procedure(p_j2k->m_validation_list, j2k_decoding_validation); + /* DEVELOPER CORNER, add your custom validation procedure */ - return image; } -/* -* Read a JPT-stream and decode file -* -*/ -opj_image_t* j2k_decode_jpt_stream(opj_j2k_t *j2k, opj_cio_t *cio, opj_codestream_info_t *cstr_info) { - opj_image_t *image = NULL; - opj_jpt_msg_header_t header; - int position; - opj_common_ptr cinfo = j2k->cinfo; +/** + * 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. + */ +bool j2k_exec ( + opj_j2k_t * p_j2k, + opj_procedure_list_t * p_procedure_list, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ) +{ + bool (** l_procedure) (opj_j2k_t * ,opj_stream_private_t *,opj_event_mgr_t *) = 00; + bool l_result = 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 = (bool (**) (opj_j2k_t * ,opj_stream_private_t *,opj_event_mgr_t *)) opj_procedure_list_get_first_procedure(p_procedure_list); + for + (i=0;i<l_nb_proc;++i) + { + l_result = l_result && ((*l_procedure) (p_j2k,p_stream,p_manager)); + ++l_procedure; + } + // and clear the procedure list at the end. + opj_procedure_list_clear(p_procedure_list); + return l_result; +} + +/** + * The default encoding validation procedure without any extension. + * + * @param p_j2k the jpeg2000 codec to validate. + * @param p_stream the input stream to validate. + * @param p_manager the user event manager. + * + * @return true if the parameters are correct. + */ +bool j2k_encoding_validation ( + opj_j2k_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ) +{ + bool l_is_valid = true; + + // preconditions + assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); + + /* STATE checking */ + /* make sure the state is at 0 */ + l_is_valid &= (p_j2k->m_specific_param.m_decoder.m_state == J2K_DEC_STATE_NONE); - j2k->cio = cio; + /* POINTER validation */ + /* make sure a p_j2k codec is present */ + l_is_valid &= (p_j2k->m_procedure_list != 00); + /* make sure a validation list is present */ + l_is_valid &= (p_j2k->m_validation_list != 00); + + if + ((p_j2k->m_cp.tdx) < (OPJ_UINT32) (1 << p_j2k->m_cp.tcps->tccps->numresolutions)) + { + opj_event_msg(p_manager, EVT_ERROR, "Number of resolutions is too high in comparison to the size of tiles\n"); + return false; + } + if + ((p_j2k->m_cp.tdy) < (OPJ_UINT32) (1 << p_j2k->m_cp.tcps->tccps->numresolutions)) + { + opj_event_msg(p_manager, EVT_ERROR, "Number of resolutions is too high in comparison to the size of tiles\n"); + return false; + } - /* create an empty image */ - image = opj_image_create0(); - j2k->image = image; + /* PARAMETER VALIDATION */ + return l_is_valid; +} - j2k->state = J2K_STATE_MHSOC; +/** + * 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. + */ +bool j2k_decoding_validation ( + opj_j2k_t *p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ) +{ + bool l_is_valid = true; - /* Initialize the header */ - jpt_init_msg_header(&header); - /* Read the first header of the message */ - jpt_read_msg_header(cinfo, cio, &header); + // preconditions + assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); + + /* STATE checking */ + /* make sure the state is at 0 */ + l_is_valid &= (p_j2k->m_specific_param.m_decoder.m_state == J2K_DEC_STATE_NONE); - position = cio_tell(cio); - if (header.Class_Id != 6) { /* 6 : Main header data-bin message */ - opj_image_destroy(image); - opj_event_msg(cinfo, EVT_ERROR, "[JPT-stream] : Expecting Main header first [class_Id %d] !\n", header.Class_Id); - return 0; - } + /* 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; +} + +/** + * The mct encoding validation procedure. + * + * @param p_j2k the jpeg2000 codec to validate. + * @param p_stream the input stream to validate. + * @param p_manager the user event manager. + * + * @return true if the parameters are correct. + */ +bool j2k_mct_validation ( + opj_j2k_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ) +{ + bool l_is_valid = true; + OPJ_UINT32 i,j; - for (;;) { - opj_dec_mstabent_t *e = NULL; - int id; - - if (!cio_numbytesleft(cio)) { - j2k_read_eoc(j2k); - return image; - } - /* data-bin read -> need to read a new header */ - if ((unsigned int) (cio_tell(cio) - position) == header.Msg_length) { - jpt_read_msg_header(cinfo, cio, &header); - position = cio_tell(cio); - if (header.Class_Id != 4) { /* 4 : Tile data-bin message */ - opj_image_destroy(image); - opj_event_msg(cinfo, EVT_ERROR, "[JPT-stream] : Expecting Tile info !\n"); - return 0; + // preconditions + assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); + + if + ((p_j2k->m_cp.rsiz & 0x8200) == 0x8200) + { + OPJ_UINT32 l_nb_tiles = p_j2k->m_cp.th * p_j2k->m_cp.tw; + opj_tcp_t * l_tcp = p_j2k->m_cp.tcps; + for + (i=0;i<l_nb_tiles;++i) + { + if + (l_tcp->mct == 2) + { + opj_tccp_t * l_tccp = l_tcp->tccps; + l_is_valid &= (l_tcp->m_mct_coding_matrix != 00); + for + (j=0;j<p_j2k->m_image->numcomps;++j) + { + l_is_valid &= ! (l_tccp->qmfbid & 1); + ++l_tccp; + } } + ++l_tcp; } - - id = cio_read(cio, 2); - if (id >> 8 != 0xff) { - opj_image_destroy(image); - opj_event_msg(cinfo, EVT_ERROR, "%.8x: expected a marker instead of %x\n", cio_tell(cio) - 2, id); - return 0; + } + return l_is_valid; +} + +/** + * Builds the cp decoder parameters to use to decode tile. + */ +bool j2k_build_decoder ( + opj_j2k_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 true; +} + +/** + * Builds the cp encoder parameters to use to encode tile. + */ +bool j2k_build_encoder ( + opj_j2k_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ) +{ + // add here initialization of cp + // copy paste of setup_encoder + return true; +} + +bool j2k_copy_default_tcp_and_create_tcd + ( + opj_j2k_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ) +{ + opj_tcp_t * l_tcp = 00; + opj_tcp_t * l_default_tcp = 00; + OPJ_UINT32 l_nb_tiles; + OPJ_UINT32 i,j; + opj_tccp_t *l_current_tccp = 00; + OPJ_UINT32 l_tccp_size; + OPJ_UINT32 l_mct_size; + opj_image_t * l_image; + OPJ_UINT32 l_mcc_records_size,l_mct_records_size; + opj_mct_data_t * l_src_mct_rec, *l_dest_mct_rec; + opj_simple_mcc_decorrelation_data_t * l_src_mcc_rec, *l_dest_mcc_rec; + OPJ_UINT32 l_offset; + + // preconditions in debug + assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); + + l_image = p_j2k->m_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;i<l_nb_tiles;++i) + { + l_current_tccp = l_tcp->tccps; + memcpy(l_tcp,l_default_tcp, sizeof(opj_tcp_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_malloc(l_mct_size); + if + (! l_tcp->m_mct_decoding_matrix ) + { + return false; + } + memcpy(l_tcp->m_mct_decoding_matrix,l_default_tcp->m_mct_decoding_matrix,l_mct_size); } - e = j2k_dec_mstab_lookup(id); - if (!(j2k->state & e->states)) { - opj_image_destroy(image); - opj_event_msg(cinfo, EVT_ERROR, "%.8x: unexpected marker %x\n", cio_tell(cio) - 2, id); - return 0; + l_mct_records_size = l_default_tcp->m_nb_max_mct_records * sizeof(opj_mct_data_t); + l_tcp->m_mct_records = opj_malloc(l_mct_records_size); + if + (! l_tcp->m_mct_records) + { + return false; } - if (e->handler) { - (*e->handler)(j2k); + 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;j<l_default_tcp->m_nb_mct_records;++j) + { + if + (l_src_mct_rec->m_data) + { + l_dest_mct_rec->m_data = opj_malloc(l_src_mct_rec->m_data_size); + if + (! l_dest_mct_rec->m_data) + { + return 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; } - if (j2k->state == J2K_STATE_MT) { - break; + 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_malloc(l_mcc_records_size); + if + (! l_tcp->m_mcc_records) + { + return false; } - if (j2k->state == J2K_STATE_NEOC) { - break; + 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;j<l_default_tcp->m_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; } - if (j2k->state == J2K_STATE_NEOC) { - j2k_read_eoc(j2k); + p_j2k->m_tcd = tcd_create(true); + if + (! p_j2k->m_tcd ) + { + return false; } - - if (j2k->state != J2K_STATE_MT) { - opj_event_msg(cinfo, EVT_WARNING, "Incomplete bitstream\n"); + if + (! tcd_init(p_j2k->m_tcd, l_image, &(p_j2k->m_cp))) + { + tcd_destroy(p_j2k->m_tcd); + p_j2k->m_tcd = 00; + opj_event_msg(p_manager, EVT_ERROR, "Cannot decode tile, memory error\n"); + return false; } - - return image; + return true; } -/* ----------------------------------------------------------------------- */ -/* J2K encoder interface */ -/* ----------------------------------------------------------------------- */ - -opj_j2k_t* j2k_create_compress(opj_common_ptr cinfo) { - opj_j2k_t *j2k = (opj_j2k_t*) opj_calloc(1, sizeof(opj_j2k_t)); - if(j2k) { - j2k->cinfo = cinfo; +/** + * Destroys the memory associated with the decoding of headers. + */ +bool j2k_destroy_header_memory ( + opj_j2k_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ) +{ + // preconditions in debug + assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); + + if + (p_j2k->m_specific_param.m_encoder.m_header_tile_data) + { + opj_free(p_j2k->m_specific_param.m_encoder.m_header_tile_data); + p_j2k->m_specific_param.m_encoder.m_header_tile_data = 0; } - return j2k; + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = 0; + return true; } -void j2k_destroy_compress(opj_j2k_t *j2k) { - int tileno; - - if(!j2k) return; - if(j2k->cp != NULL) { - opj_cp_t *cp = j2k->cp; - - if(cp->comment) { - opj_free(cp->comment); - } - if(cp->matrice) { - opj_free(cp->matrice); - } - for (tileno = 0; tileno < cp->tw * cp->th; tileno++) { - opj_free(cp->tcps[tileno].tccps); +/** + * Sets up the decoder decoding parameters using user parameters. + * Decoding parameters are stored in p_j2k->m_cp. + * + * @param p_j2k J2K codec + * @param p_parameters decompression parameters + * @deprecated +*/ +void j2k_setup_decoder( + opj_j2k_t *p_j2k, + opj_dparameters_t *p_parameters + ) +{ + if + (p_j2k && p_parameters) + { + /* create and initialize the coding parameters structure */ + p_j2k->m_cp.m_specific_param.m_dec.m_reduce = p_parameters->cp_reduce; + p_j2k->m_cp.m_specific_param.m_dec.m_layer = p_parameters->cp_layer; + p_j2k->m_specific_param.m_decoder.m_discard_tiles = p_parameters->m_use_restrict_decode; + if + (p_parameters->m_use_restrict_decode) + { + p_j2k->m_specific_param.m_decoder.m_start_tile_x = p_parameters->m_decode_start_x; + p_j2k->m_specific_param.m_decoder.m_start_tile_y = p_parameters->m_decode_start_y; + p_j2k->m_specific_param.m_decoder.m_end_tile_x = p_parameters->m_decode_end_x; + p_j2k->m_specific_param.m_decoder.m_end_tile_y = p_parameters->m_decode_end_y; } - opj_free(cp->tcps); - opj_free(cp); - } - opj_free(j2k); +#ifdef USE_JPWL + cp->correct = parameters->jpwl_correct; + cp->exp_comps = parameters->jpwl_exp_comps; + cp->max_tiles = parameters->jpwl_max_tiles; +#endif /* USE_JPWL */ + } } -void j2k_setup_encoder(opj_j2k_t *j2k, opj_cparameters_t *parameters, opj_image_t *image) { - int i, j, tileno, numpocs_tile; - opj_cp_t *cp = NULL; - - if(!j2k || !parameters || ! image) { +void j2k_setup_encoder(opj_j2k_t *p_j2k, opj_cparameters_t *parameters, opj_image_t *image, struct opj_event_mgr * p_manager) { + OPJ_UINT32 i, j, tileno, numpocs_tile; + opj_cp_t *cp = 00; + bool l_res; + if(!p_j2k || !parameters || ! image) { return; } - - /* create and initialize the coding parameters structure */ - cp = (opj_cp_t*) opj_calloc(1, sizeof(opj_cp_t)); - + /* keep a link to cp so that we can destroy it later in j2k_destroy_compress */ - j2k->cp = cp; - + cp = &(p_j2k->m_cp); + /* set default values for cp */ cp->tw = 1; cp->th = 1; @@ -2047,18 +7762,20 @@ void j2k_setup_encoder(opj_j2k_t *j2k, opj_cparameters_t *parameters, opj_image_ /* copy user encoding parameters */ - cp->cinema = parameters->cp_cinema; - cp->max_comp_size = parameters->max_comp_size; + cp->m_specific_param.m_enc.m_cinema = parameters->cp_cinema; + cp->m_specific_param.m_enc.m_max_comp_size = parameters->max_comp_size; cp->rsiz = parameters->cp_rsiz; - cp->disto_alloc = parameters->cp_disto_alloc; - cp->fixed_alloc = parameters->cp_fixed_alloc; - cp->fixed_quality = parameters->cp_fixed_quality; + cp->m_specific_param.m_enc.m_disto_alloc = parameters->cp_disto_alloc; + cp->m_specific_param.m_enc.m_fixed_alloc = parameters->cp_fixed_alloc; + cp->m_specific_param.m_enc.m_fixed_quality = parameters->cp_fixed_quality; /* mod fixed_quality */ - if(parameters->cp_matrice) { - size_t array_size = parameters->tcp_numlayers * parameters->numresolution * 3 * sizeof(int); - cp->matrice = (int *) opj_malloc(array_size); - memcpy(cp->matrice, parameters->cp_matrice, array_size); + if + (parameters->cp_matrice) + { + size_t array_size = parameters->tcp_numlayers * parameters->numresolution * 3 * sizeof(OPJ_INT32); + cp->m_specific_param.m_enc.m_matrice = (OPJ_INT32 *) opj_malloc(array_size); + memcpy(cp->m_specific_param.m_enc.m_matrice, parameters->cp_matrice, array_size); } /* tiles */ @@ -2089,24 +7806,20 @@ void j2k_setup_encoder(opj_j2k_t *j2k, opj_cparameters_t *parameters, opj_image_ cp->tdy = image->y1 - cp->ty0; } - if(parameters->tp_on){ - cp->tp_flag = parameters->tp_flag; - cp->tp_on = 1; + if + (parameters->tp_on) + { + cp->m_specific_param.m_enc.m_tp_flag = parameters->tp_flag; + cp->m_specific_param.m_enc.m_tp_on = 1; } - cp->img_size = 0; - for(i=0;i<image->numcomps ;i++){ - cp->img_size += (image->comps[i].w *image->comps[i].h * image->comps[i].prec); - } - - #ifdef USE_JPWL /* calculate JPWL encoding parameters */ if (parameters->jpwl_epc_on) { - int i; + OPJ_INT32 i; /* set JPWL on */ cp->epc_on = true; @@ -2160,18 +7873,24 @@ void j2k_setup_encoder(opj_j2k_t *j2k, opj_cparameters_t *parameters, opj_image_ /* initialize the mutiple tiles */ /* ---------------------------- */ cp->tcps = (opj_tcp_t*) opj_calloc(cp->tw * cp->th, sizeof(opj_tcp_t)); - + if + (parameters->numpocs) + { + /* initialisation of POC */ + l_res = j2k_check_poc_val(parameters->POC,parameters->numpocs, parameters->numresolution, image->numcomps, parameters->tcp_numlayers, p_manager); + // TODO + } for (tileno = 0; tileno < cp->tw * cp->th; tileno++) { opj_tcp_t *tcp = &cp->tcps[tileno]; tcp->numlayers = parameters->tcp_numlayers; for (j = 0; j < tcp->numlayers; j++) { - if(cp->cinema){ - if (cp->fixed_quality) { + if(cp->m_specific_param.m_enc.m_cinema){ + if (cp->m_specific_param.m_enc.m_fixed_quality) { tcp->distoratio[j] = parameters->tcp_distoratio[j]; } tcp->rates[j] = parameters->tcp_rates[j]; }else{ - if (cp->fixed_quality) { /* add fixed_quality */ + if (cp->m_specific_param.m_enc.m_fixed_quality) { /* add fixed_quality */ tcp->distoratio[j] = parameters->tcp_distoratio[j]; } else { tcp->rates[j] = parameters->tcp_rates[j]; @@ -2182,12 +7901,17 @@ void j2k_setup_encoder(opj_j2k_t *j2k, opj_cparameters_t *parameters, opj_image_ tcp->prg = parameters->prog_order; tcp->mct = parameters->tcp_mct; + + numpocs_tile = 0; tcp->POC = 0; - if (parameters->numpocs) { + if + (parameters->numpocs) + { /* initialisation of POC */ tcp->POC = 1; - for (i = 0; i < parameters->numpocs; i++) { + // TODO + for (i = 0; i < (unsigned int) parameters->numpocs; i++) { if((tileno == parameters->POC[i].tile - 1) || (parameters->POC[i].tile == -1)) { opj_poc_t *tcp_poc = &tcp->pocs[numpocs_tile]; tcp_poc->resno0 = parameters->POC[numpocs_tile].resno0; @@ -2206,6 +7930,44 @@ void j2k_setup_encoder(opj_j2k_t *j2k, opj_cparameters_t *parameters, opj_image_ } tcp->tccps = (opj_tccp_t*) opj_calloc(image->numcomps, sizeof(opj_tccp_t)); + if + (parameters->mct_data) + { + OPJ_UINT32 lMctSize = image->numcomps * image->numcomps * sizeof(OPJ_FLOAT32); + OPJ_FLOAT32 * lTmpBuf = opj_malloc(lMctSize); + OPJ_INT32 * l_dc_shift = (OPJ_INT32 *) ((OPJ_BYTE *) parameters->mct_data + lMctSize); + tcp->mct = 2; + tcp->m_mct_coding_matrix = opj_malloc(lMctSize); + memcpy(tcp->m_mct_coding_matrix,parameters->mct_data,lMctSize); + memcpy(lTmpBuf,parameters->mct_data,lMctSize); + tcp->m_mct_decoding_matrix = opj_malloc(lMctSize); + assert(opj_matrix_inversion_f(lTmpBuf,(tcp->m_mct_decoding_matrix),image->numcomps)); + tcp->mct_norms = opj_malloc(image->numcomps * sizeof(OPJ_FLOAT64)); + opj_calculate_norms(tcp->mct_norms,image->numcomps,tcp->m_mct_decoding_matrix); + opj_free(lTmpBuf); + for + (i = 0; i < image->numcomps; i++) + { + opj_tccp_t *tccp = &tcp->tccps[i]; + tccp->m_dc_level_shift = l_dc_shift[i]; + } + j2k_setup_mct_encoding(tcp,image); + } + else + { + for + (i = 0; i < image->numcomps; i++) + { + opj_tccp_t *tccp = &tcp->tccps[i]; + opj_image_comp_t * l_comp = &(image->comps[i]); + if + (! l_comp->sgnd) + { + tccp->m_dc_level_shift = 1 << (l_comp->prec - 1); + } + } + } + for (i = 0; i < image->numcomps; i++) { opj_tccp_t *tccp = &tcp->tccps[i]; @@ -2278,232 +8040,1268 @@ void j2k_setup_encoder(opj_j2k_t *j2k, opj_cparameters_t *parameters, opj_image_ } } } - + dwt_calc_explicit_stepsizes(tccp, image->comps[i].prec); } } + if + (parameters->mct_data) + { + opj_free(parameters->mct_data); + parameters->mct_data = 00; + } +} + +bool j2k_write_first_tile_part ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 p_total_data_size, + opj_stream_private_t *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 compno; + OPJ_UINT32 l_nb_bytes_written = 0; + OPJ_UINT32 l_current_nb_bytes_written; + OPJ_BYTE * l_begin_data = 00; + + opj_tcp_t *l_tcp = 00; + opj_tcd_t * l_tcd = 00; + opj_cp_t * l_cp = 00; + + l_tcd = p_j2k->m_tcd; + l_cp = &(p_j2k->m_cp); + l_tcp = l_cp->tcps + p_j2k->m_current_tile_number; + + l_tcd->cur_pino = 0; + /*Get number of tile parts*/ + + p_j2k->m_specific_param.m_encoder.m_current_poc_tile_part_number = 0; + /* INDEX >> */ + + /* << INDEX */ + l_current_nb_bytes_written = 0; + l_begin_data = p_data; + if + (! j2k_write_sot(p_j2k,p_data,&l_current_nb_bytes_written,p_stream,p_manager)) + { + return false; + } + l_nb_bytes_written += l_current_nb_bytes_written; + p_data += l_current_nb_bytes_written; + p_total_data_size -= l_current_nb_bytes_written; + + if + (l_cp->m_specific_param.m_enc.m_cinema == 0) + { + for + (compno = 1; compno < p_j2k->m_image->numcomps; compno++) + { + l_current_nb_bytes_written = 0; + j2k_write_coc_in_memory(p_j2k,compno,p_data,&l_current_nb_bytes_written,p_manager); + l_nb_bytes_written += l_current_nb_bytes_written; + p_data += l_current_nb_bytes_written; + p_total_data_size -= l_current_nb_bytes_written; + + l_current_nb_bytes_written = 0; + j2k_write_qcc_in_memory(p_j2k,compno,p_data,&l_current_nb_bytes_written,p_manager); + l_nb_bytes_written += l_current_nb_bytes_written; + p_data += l_current_nb_bytes_written; + p_total_data_size -= l_current_nb_bytes_written; + } + if + (l_cp->tcps[p_j2k->m_current_tile_number].numpocs) + { + l_current_nb_bytes_written = 0; + j2k_write_poc_in_memory(p_j2k,p_data,&l_current_nb_bytes_written,p_manager); + l_nb_bytes_written += l_current_nb_bytes_written; + p_data += l_current_nb_bytes_written; + p_total_data_size -= l_current_nb_bytes_written; + } + } + l_current_nb_bytes_written = 0; + if + (! j2k_write_sod(p_j2k,l_tcd,p_data,&l_current_nb_bytes_written,p_total_data_size,p_stream,p_manager)) + { + return false; + } + l_nb_bytes_written += l_current_nb_bytes_written; + * p_data_written = l_nb_bytes_written; + + /* Writing Psot in SOT marker */ + opj_write_bytes(l_begin_data + 6,l_nb_bytes_written,4); /* PSOT */ + if + (l_cp->m_specific_param.m_enc.m_cinema) + { + j2k_update_tlm(p_j2k,l_nb_bytes_written); + } + return true; } -bool j2k_encode(opj_j2k_t *j2k, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info) { - int tileno, compno; - opj_cp_t *cp = NULL; +bool j2k_write_all_tile_parts( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 p_total_data_size, + opj_stream_private_t *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 tilepartno=0; + OPJ_UINT32 l_nb_bytes_written = 0; + OPJ_UINT32 l_current_nb_bytes_written; + OPJ_UINT32 l_part_tile_size; + OPJ_UINT32 tot_num_tp; + OPJ_UINT32 pino; + + OPJ_BYTE * l_begin_data; + opj_tcp_t *l_tcp = 00; + opj_tcd_t * l_tcd = 00; + opj_cp_t * l_cp = 00; + - opj_tcd_t *tcd = NULL; /* TCD component */ + l_tcd = p_j2k->m_tcd; + l_cp = &(p_j2k->m_cp); + l_tcp = l_cp->tcps + p_j2k->m_current_tile_number; + + /*Get number of tile parts*/ + tot_num_tp = j2k_get_num_tp(l_cp,0,p_j2k->m_current_tile_number); + for + (tilepartno = 1; tilepartno < tot_num_tp ; ++tilepartno) + { + p_j2k->m_specific_param.m_encoder.m_current_poc_tile_part_number = tilepartno; + l_current_nb_bytes_written = 0; + l_part_tile_size = 0; + l_begin_data = p_data; + if + (! j2k_write_sot(p_j2k,p_data,&l_current_nb_bytes_written,p_stream,p_manager)) + { + return false; + } + l_nb_bytes_written += l_current_nb_bytes_written; + p_data += l_current_nb_bytes_written; + p_total_data_size -= l_current_nb_bytes_written; + l_part_tile_size += l_nb_bytes_written; + + l_current_nb_bytes_written = 0; + if + (! j2k_write_sod(p_j2k,l_tcd,p_data,&l_current_nb_bytes_written,p_total_data_size,p_stream,p_manager)) + { + return false; + } + p_data += l_current_nb_bytes_written; + l_nb_bytes_written += l_current_nb_bytes_written; + p_total_data_size -= l_current_nb_bytes_written; + l_part_tile_size += l_nb_bytes_written; + + /* Writing Psot in SOT marker */ + opj_write_bytes(l_begin_data + 6,l_part_tile_size,4); /* PSOT */ - j2k->cio = cio; - j2k->image = image; + if + (l_cp->m_specific_param.m_enc.m_cinema) + { + j2k_update_tlm(p_j2k,l_part_tile_size); + } + ++p_j2k->m_specific_param.m_encoder.m_current_tile_part_number; + } + for + (pino = 1; pino <= l_tcp->numpocs; ++pino) + { + l_tcd->cur_pino = pino; + /*Get number of tile parts*/ + tot_num_tp = j2k_get_num_tp(l_cp,pino,p_j2k->m_current_tile_number); + for + (tilepartno = 0; tilepartno < tot_num_tp ; ++tilepartno) + { + p_j2k->m_specific_param.m_encoder.m_current_poc_tile_part_number = tilepartno; + l_current_nb_bytes_written = 0; + l_part_tile_size = 0; + l_begin_data = p_data; + if + (! j2k_write_sot(p_j2k,p_data,&l_current_nb_bytes_written,p_stream,p_manager)) + { + return false; + } + l_nb_bytes_written += l_current_nb_bytes_written; + p_data += l_current_nb_bytes_written; + p_total_data_size -= l_current_nb_bytes_written; + l_part_tile_size += l_current_nb_bytes_written; + + l_current_nb_bytes_written = 0; + if + (! j2k_write_sod(p_j2k,l_tcd,p_data,&l_current_nb_bytes_written,p_total_data_size,p_stream,p_manager)) + { + return false; + } + l_nb_bytes_written += l_current_nb_bytes_written; + p_data += l_current_nb_bytes_written; + p_total_data_size -= l_current_nb_bytes_written; + l_part_tile_size += l_current_nb_bytes_written; + + /* Writing Psot in SOT marker */ + opj_write_bytes(l_begin_data + 6,l_part_tile_size,4); /* PSOT */ + + if + (l_cp->m_specific_param.m_enc.m_cinema) + { + j2k_update_tlm(p_j2k,l_part_tile_size); + } + ++p_j2k->m_specific_param.m_encoder.m_current_tile_part_number; + } + } + *p_data_written = l_nb_bytes_written; + return true; +} - cp = j2k->cp; - /* j2k_dump_cp(stdout, image, cp); */ +bool j2k_pre_write_tile ( + opj_j2k_t * p_j2k, + OPJ_UINT32 p_tile_index, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ) +{ + if + (p_tile_index != p_j2k->m_current_tile_number) + { + opj_event_msg(p_manager, EVT_ERROR, "The given tile index does not match." ); + return false; + } - /* INDEX >> */ - j2k->cstr_info = cstr_info; - if (cstr_info) { - int compno; - cstr_info->tile = (opj_tile_info_t *) opj_malloc(cp->tw * cp->th * sizeof(opj_tile_info_t)); - cstr_info->image_w = image->x1 - image->x0; - cstr_info->image_h = image->y1 - image->y0; - cstr_info->prog = (&cp->tcps[0])->prg; - cstr_info->tw = cp->tw; - cstr_info->th = cp->th; - cstr_info->tile_x = cp->tdx; /* new version parser */ - cstr_info->tile_y = cp->tdy; /* new version parser */ - cstr_info->tile_Ox = cp->tx0; /* new version parser */ - cstr_info->tile_Oy = cp->ty0; /* new version parser */ - cstr_info->numcomps = image->numcomps; - cstr_info->numlayers = (&cp->tcps[0])->numlayers; - cstr_info->numdecompos = (int*) opj_malloc(image->numcomps * sizeof(int)); - for (compno=0; compno < image->numcomps; compno++) { - cstr_info->numdecompos[compno] = (&cp->tcps[0])->tccps->numresolutions - 1; - } - cstr_info->D_max = 0.0; /* ADD Marcela */ - cstr_info->main_head_start = cio_tell(cio); /* position of SOC */ - cstr_info->maxmarknum = 100; - cstr_info->marker = (opj_marker_info_t *) opj_malloc(cstr_info->maxmarknum * sizeof(opj_marker_info_t)); - cstr_info->marknum = 0; + opj_event_msg(p_manager, EVT_INFO, "tile number %d / %d\n", p_j2k->m_current_tile_number + 1, p_j2k->m_cp.tw * p_j2k->m_cp.th); + + p_j2k->m_specific_param.m_encoder.m_current_tile_part_number = 0; + p_j2k->m_tcd->cur_totnum_tp = p_j2k->m_cp.tcps[p_tile_index].m_nb_tile_parts; + p_j2k->m_specific_param.m_encoder.m_current_poc_tile_part_number = 0; + /* initialisation before tile encoding */ + if + (! tcd_init_encode_tile(p_j2k->m_tcd, p_j2k->m_current_tile_number)) + { + return false; } - /* << INDEX */ + return true; +} - j2k_write_soc(j2k); - j2k_write_siz(j2k); - j2k_write_cod(j2k); - j2k_write_qcd(j2k); +/** + * Writes a tile. + * @param p_j2k the jpeg2000 codec. + * @param p_stream the stream to write data to. + * @param p_manager the user event manager. + */ +bool j2k_write_tile ( + opj_j2k_t * p_j2k, + OPJ_UINT32 p_tile_index, + OPJ_BYTE * p_data, + OPJ_UINT32 p_data_size, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ) +{ + if + (! j2k_pre_write_tile(p_j2k,p_tile_index,p_stream,p_manager)) + { + return false; + } + return j2k_post_write_tile(p_j2k,p_data,p_data_size,p_stream,p_manager); +} - if(cp->cinema){ - for (compno = 1; compno < image->numcomps; compno++) { - j2k_write_coc(j2k, compno); - j2k_write_qcc(j2k, compno); - } +/** + * Writes a tile. + * @param p_j2k the jpeg2000 codec. + * @param p_stream the stream to write data to. + * @param p_manager the user event manager. + */ +bool j2k_post_write_tile ( + opj_j2k_t * p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 p_data_size, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ) +{ + opj_tcd_t * l_tcd = 00; + opj_cp_t * l_cp = 00; + opj_tcp_t * l_tcp = 00; + OPJ_UINT32 l_nb_bytes_written; + OPJ_BYTE * l_current_data = 00; + OPJ_UINT32 l_tile_size = 0; + OPJ_UINT32 l_available_data; + + assert(p_j2k->m_specific_param.m_encoder.m_encoded_tile_data); + + l_tcd = p_j2k->m_tcd; + l_cp = &(p_j2k->m_cp); + l_tcp = l_cp->tcps + p_j2k->m_current_tile_number; + + l_tile_size = p_j2k->m_specific_param.m_encoder.m_encoded_tile_size; + l_available_data = l_tile_size; + l_current_data = p_j2k->m_specific_param.m_encoder.m_encoded_tile_data; + if + (! tcd_copy_tile_data(l_tcd,p_data,p_data_size)) + { + opj_event_msg(p_manager, EVT_ERROR, "Size mismtach between tile data and sent data." ); + return false; + } + + l_nb_bytes_written = 0; + if + (! j2k_write_first_tile_part(p_j2k,l_current_data,&l_nb_bytes_written,l_available_data,p_stream,p_manager)) + { + return false; } + l_current_data += l_nb_bytes_written; + l_available_data -= l_nb_bytes_written; + + l_nb_bytes_written = 0; + if + (! j2k_write_all_tile_parts(p_j2k,l_current_data,&l_nb_bytes_written,l_available_data,p_stream,p_manager)) + { + return false; + } + + l_available_data -= l_nb_bytes_written; + l_nb_bytes_written = l_tile_size - l_available_data; + + if + (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_encoded_tile_data,l_nb_bytes_written,p_manager) != l_nb_bytes_written) + { + return false; + } + ++p_j2k->m_current_tile_number; + return true; +} - for (compno = 0; compno < image->numcomps; compno++) { - opj_tcp_t *tcp = &cp->tcps[0]; - if (tcp->tccps[compno].roishift) - j2k_write_rgn(j2k, compno, 0); +/** + * 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. + */ +bool j2k_read_tile_header ( + opj_j2k_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, + 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_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 == J2K_DEC_STATE_EOC) + { + l_current_marker = J2K_MS_EOC; } - if (cp->comment != NULL) { - j2k_write_com(j2k); + else if + (p_j2k->m_specific_param.m_decoder.m_state != J2K_DEC_STATE_TPHSOT) + { + return 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(p_manager, EVT_ERROR, "Stream too short\n"); + return 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_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(p_manager, EVT_ERROR, "Marker is not compliant with its position\n"); + return 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_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 false; + } + p_j2k->m_specific_param.m_decoder.m_header_data_size = l_marker_size; - j2k->totnum_tp = j2k_calculate_tp(cp,image->numcomps,image,j2k); - /* TLM Marker*/ - if(cp->cinema){ - j2k_write_tlm(j2k); - if (cp->cinema == CINEMA4K_24) { - j2k_write_poc(j2k); + } + 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(p_manager, EVT_ERROR, "Stream too short\n"); + return 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(p_manager, EVT_ERROR, "Marker is not compliant with its position\n"); + return 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(p_manager, EVT_ERROR, "Stream too short\n"); + return 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(p_manager, EVT_ERROR, "Stream too short\n"); + return 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(p_j2k,p_stream,p_manager)) + { + return 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_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(p_manager, EVT_ERROR, "Stream too short\n"); + return 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 != J2K_DEC_STATE_EOC) + { + p_j2k->m_current_tile_number = 0; + p_j2k->m_specific_param.m_decoder.m_state = J2K_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 = false; + return true; + } + } + if + (! tcd_init_decode_tile(p_j2k->m_tcd, p_j2k->m_current_tile_number)) + { + opj_event_msg(p_manager, EVT_ERROR, "Cannot decode tile, memory error\n"); + return false; + } + *p_tile_index = p_j2k->m_current_tile_number; + *p_go_on = 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 |= J2K_DEC_STATE_DATA; + return true; +} - /* uncomment only for testing JPSEC marker writing */ - /* j2k_write_sec(j2k); */ +bool j2k_decode_tile ( + opj_j2k_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_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 & J2K_DEC_STATE_DATA) || p_tile_index != p_j2k->m_current_tile_number) + { + return 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 false; + } + if + (! tcd_decode_tile(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 |= J2K_DEC_STATE_ERR; + return false; + } + if + (! tcd_update_tile_data(p_j2k->m_tcd,p_data,p_data_size)) + { + return 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 &= (~J2K_DEC_STATE_DATA); + if + (p_j2k->m_specific_param.m_decoder.m_state != J2K_DEC_STATE_EOC) + { + if + (opj_stream_read_data(p_stream,l_data,2,p_manager) != 2) + { + opj_event_msg(p_manager, EVT_ERROR, "Stream too short\n"); + return 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 = J2K_DEC_STATE_EOC; + } + else if + (l_current_marker != J2K_MS_SOT) + { + opj_event_msg(p_manager, EVT_ERROR, "Stream too short, expected SOT\n"); + return false; + } + } + return true; +} + - /* INDEX >> */ - if(cstr_info) { - cstr_info->main_head_end = cio_tell(cio) - 1; +/** + * Ends the compression procedures and possibiliy add data to be read after the + * codestream. + */ +bool j2k_end_compress(opj_j2k_t *p_j2k, struct opj_stream_private *p_stream, struct opj_event_mgr * p_manager) +{ + /* customization of the encoding */ + j2k_setup_end_compress(p_j2k); + + if + (! j2k_exec (p_j2k,p_j2k->m_procedure_list,p_stream,p_manager)) + { + return false; } - /* << INDEX */ - /**** Main Header ENDS here ***/ + return true; +} - /* create the tile encoder */ - tcd = tcd_create(j2k->cinfo); +/** + * 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. + */ +bool j2k_read_header( + opj_j2k_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, + struct opj_stream_private *p_stream, + struct opj_event_mgr * 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 false; + } - /* encode each tile */ - for (tileno = 0; tileno < cp->tw * cp->th; tileno++) { - int pino; - int tilepartno=0; - /* UniPG>> */ - int acc_pack_num = 0; - /* <<UniPG */ + /* 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 false; + } + /* customization of the encoding */ + j2k_setup_header_reading(p_j2k); - opj_tcp_t *tcp = &cp->tcps[tileno]; - opj_event_msg(j2k->cinfo, EVT_INFO, "tile number %d / %d\n", tileno + 1, cp->tw * cp->th); - - j2k->curtileno = tileno; - j2k->cur_tp_num = 0; - tcd->cur_totnum_tp = j2k->cur_totnum_tp[j2k->curtileno]; - /* initialisation before tile encoding */ - if (tileno == 0) { - tcd_malloc_encode(tcd, image, cp, j2k->curtileno); - } else { - tcd_init_encode(tcd, image, cp, j2k->curtileno); - } - - /* INDEX >> */ - if(cstr_info) { - cstr_info->tile[j2k->curtileno].start_pos = cio_tell(cio) + j2k->pos_correction; - } - /* << INDEX */ - - for(pino = 0; pino <= tcp->numpocs; pino++) { - int tot_num_tp; - tcd->cur_pino=pino; - - /*Get number of tile parts*/ - tot_num_tp = j2k_get_num_tp(cp,pino,tileno); - tcd->tp_pos = cp->tp_pos; - - for(tilepartno = 0; tilepartno < tot_num_tp ; tilepartno++){ - j2k->tp_num = tilepartno; - /* INDEX >> */ - if(cstr_info) - cstr_info->tile[j2k->curtileno].tp[j2k->cur_tp_num].tp_start_pos = - cio_tell(cio) + j2k->pos_correction; - /* << INDEX */ - j2k_write_sot(j2k); - - if(j2k->cur_tp_num == 0 && cp->cinema == 0){ - for (compno = 1; compno < image->numcomps; compno++) { - j2k_write_coc(j2k, compno); - j2k_write_qcc(j2k, compno); - } - if (cp->tcps[tileno].numpocs) { - j2k_write_poc(j2k); - } - } + /* 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 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 true; +} - /* INDEX >> */ - if(cstr_info) - cstr_info->tile[j2k->curtileno].tp[j2k->cur_tp_num].tp_end_header = - cio_tell(cio) + j2k->pos_correction + 1; - /* << INDEX */ - - j2k_write_sod(j2k, tcd); - - /* INDEX >> */ - if(cstr_info) { - cstr_info->tile[j2k->curtileno].tp[j2k->cur_tp_num].tp_end_pos = - cio_tell(cio) + j2k->pos_correction - 1; - cstr_info->tile[j2k->curtileno].tp[j2k->cur_tp_num].tp_start_pack = - acc_pack_num; - cstr_info->tile[j2k->curtileno].tp[j2k->cur_tp_num].tp_numpacks = - cstr_info->packno - acc_pack_num; - acc_pack_num = cstr_info->packno; - } - /* << INDEX */ +/** + * The read header procedure. + */ +bool j2k_read_header_procedure( + opj_j2k_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_DEC_STATE_MHSOC; - j2k->cur_tp_num++; - } + if + (! j2k_read_soc(p_j2k,p_stream,p_manager)) + { + opj_event_msg(p_manager, EVT_ERROR, "Expected a SOC marker \n"); + return false; + } + if + (opj_stream_read_data(p_stream,p_j2k->m_specific_param.m_decoder.m_header_data,2,p_manager) != 2) + { + opj_event_msg(p_manager, EVT_ERROR, "Stream too short\n"); + return false; + } + opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data,&l_current_marker,2); + + while + (l_current_marker != J2K_MS_SOT) + { + if + (opj_stream_read_data(p_stream,p_j2k->m_specific_param.m_decoder.m_header_data,2,p_manager) != 2) + { + opj_event_msg(p_manager, EVT_ERROR, "Stream too short\n"); + return false; } - if(cstr_info) { - cstr_info->tile[j2k->curtileno].end_pos = cio_tell(cio) + j2k->pos_correction - 1; + opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data,&l_marker_size,2); + l_marker_size -= 2; + /*if + (l_current_marker < 0xff00) + { + opj_event_msg(p_manager, EVT_ERROR, "%.8x: expected a marker instead of %x\n", opj_stream_tell(p_stream) - 2, l_current_marker); + return 0; } + */ + 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(p_manager, EVT_ERROR, "Marker is not compliant with its position\n"); + return 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_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 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(p_manager, EVT_ERROR, "Stream too short\n"); + return 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(p_manager, EVT_ERROR, "Marker is not compliant with its position\n"); + return false; + } + if + (opj_stream_read_data(p_stream,p_j2k->m_specific_param.m_decoder.m_header_data,2,p_manager) != 2) + { + opj_event_msg(p_manager, EVT_ERROR, "Stream too short\n"); + return false; + } + 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_DEC_STATE_TPHSOT; + return true; +} - /* - if (tile->PPT) { // BAD PPT !!! - FILE *PPT_file; - int i; - PPT_file=fopen("PPT","rb"); - fprintf(stderr,"%c%c%c%c",255,97,tile->len_ppt/256,tile->len_ppt%256); - for (i=0;i<tile->len_ppt;i++) { - unsigned char elmt; - fread(&elmt, 1, 1, PPT_file); - fwrite(&elmt,1,1,f); + +/** + * Reads the tiles. + */ +bool j2k_decode_tiles ( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager) +{ + bool l_go_on = true; + OPJ_UINT32 l_current_tile_no; + OPJ_UINT32 l_data_size,l_max_data_size; + OPJ_INT32 l_tile_x0,l_tile_y0,l_tile_x1,l_tile_y1; + OPJ_UINT32 l_nb_comps; + OPJ_BYTE * l_current_data; + + l_current_data = opj_malloc(1000); + if + (! l_current_data) + { + return false; + } + l_max_data_size = 1000; + + while + (true) + { + if + (! j2k_read_tile_header( + p_j2k,&l_current_tile_no, + &l_data_size, + &l_tile_x0, + &l_tile_y0, + &l_tile_x1, + &l_tile_y1, + &l_nb_comps, + &l_go_on, + p_stream, + p_manager)) + { + return false; } - fclose(PPT_file); - unlink("PPT"); + if + (! l_go_on) + { + break; + } + if + (l_data_size > l_max_data_size) + { + l_current_data = opj_realloc(l_current_data,l_data_size); + if + (! l_current_data) + { + return false; + } + l_max_data_size = l_data_size; + } + if + (! j2k_decode_tile(p_j2k,l_current_tile_no,l_current_data,l_data_size,p_stream,p_manager)) + { + opj_free(l_current_data); + return false; + } + if + (! j2k_update_image_data(p_j2k->m_tcd,l_current_data)) + { + opj_free(l_current_data); + return false; } - */ } + opj_free(l_current_data); + return true; +} - /* destroy the tile encoder */ - tcd_free_encode(tcd); - tcd_destroy(tcd); - opj_free(j2k->cur_totnum_tp); - j2k_write_eoc(j2k); - if(cstr_info) { - cstr_info->codestream_size = cio_tell(cio) + j2k->pos_correction; - /* UniPG>> */ - /* The following adjustment is done to adjust the codestream size */ - /* if SOD is not at 0 in the buffer. Useful in case of JP2, where */ - /* the first bunch of bytes is not in the codestream */ - cstr_info->codestream_size -= cstr_info->main_head_start; - /* <<UniPG */ - } -#ifdef USE_JPWL - /* - preparation of JPWL marker segments - */ - if(cp->epc_on) { - /* encode according to JPWL */ - jpwl_encode(j2k, cio, image); +/** + * Decodes the tiles of the stream. + */ +opj_image_t * j2k_decode( + opj_j2k_t * p_j2k, + opj_stream_private_t * p_stream, + opj_event_mgr_t * p_manager) +{ + /* customization of the encoding */ + j2k_setup_decoding(p_j2k); + + /* write 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 p_j2k->m_image; +} +/** + * Encodes all the tiles in a row. + */ +bool j2k_encode( + opj_j2k_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ) +{ + OPJ_UINT32 i; + OPJ_UINT32 l_nb_tiles; + OPJ_UINT32 l_max_tile_size, l_current_tile_size; + OPJ_BYTE * l_current_data; + + // preconditions + assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); + + l_current_data = opj_malloc(1000); + if + (! l_current_data) + { + return false; } -#endif /* USE_JPWL */ + l_max_tile_size = 1000; + + l_nb_tiles = p_j2k->m_cp.th * p_j2k->m_cp.tw; + for + (i=0;i<l_nb_tiles;++i) + { + if + (! j2k_pre_write_tile(p_j2k,i,p_stream,p_manager)) + { + opj_free(l_current_data); + return false; + } + l_current_tile_size = tcd_get_encoded_tile_size(p_j2k->m_tcd); + if + (l_current_tile_size > l_max_tile_size) + { + l_current_data = opj_realloc(l_current_data,l_current_tile_size); + if + (! l_current_data) + { + return false; + } + l_max_tile_size = l_current_tile_size; + } + j2k_get_tile_data(p_j2k->m_tcd,l_current_data); + if + (! j2k_post_write_tile (p_j2k,l_current_data,l_current_tile_size,p_stream,p_manager)) + { + return false; + } + } + opj_free(l_current_data); + return true; +} + + +/** + * Ends the decompression procedures and possibiliy add data to be read after the + * codestream. + */ +bool j2k_end_decompress( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager) +{ return true; } +void j2k_get_tile_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data) +{ + OPJ_UINT32 i,j,k = 0; + OPJ_UINT32 l_width,l_height,l_stride, l_offset_x,l_offset_y, l_image_width; + opj_image_comp_t * l_img_comp = 00; + opj_tcd_tilecomp_t * l_tilec = 00; + opj_image_t * l_image = 00; + OPJ_UINT32 l_size_comp, l_remaining; + OPJ_INT32 * l_src_ptr; + l_tilec = p_tcd->tcd_image->tiles->comps; + l_image = p_tcd->image; + l_img_comp = l_image->comps; + for + (i=0;i<p_tcd->image->numcomps;++i) + { + l_size_comp = l_img_comp->prec >> 3; /*(/ 8)*/ + l_remaining = l_img_comp->prec & 7; /* (%8) */ + if + (l_remaining) + { + ++l_size_comp; + } + if + (l_size_comp == 3) + { + l_size_comp = 4; + } + l_width = (l_tilec->x1 - l_tilec->x0); + l_height = (l_tilec->y1 - l_tilec->y0); + l_offset_x = int_ceildiv(l_image->x0, l_img_comp->dx); + l_offset_y = int_ceildiv(l_image->y0, l_img_comp->dy); + l_image_width = int_ceildiv(l_image->x1 - l_image->x0, l_img_comp->dx); + l_stride = l_image_width - l_width; + l_src_ptr = l_img_comp->data + (l_tilec->x0 - l_offset_x) + (l_tilec->y0 - l_offset_y) * l_image_width; + + switch + (l_size_comp) + { + case 1: + { + OPJ_CHAR * l_dest_ptr = (OPJ_CHAR*) p_data; + if + (l_img_comp->sgnd) + { + for + (j=0;j<l_height;++j) + { + for + (k=0;k<l_width;++k) + { + *(l_dest_ptr) = (OPJ_CHAR) (*l_src_ptr); + ++l_dest_ptr; + ++l_src_ptr; + } + l_src_ptr += l_stride; + } + } + else + { + for + (j=0;j<l_height;++j) + { + for + (k=0;k<l_width;++k) + { + *(l_dest_ptr) = (*l_src_ptr)&0xff; + ++l_dest_ptr; + ++l_src_ptr; + } + l_src_ptr += l_stride; + } + } + p_data = (OPJ_BYTE*) l_dest_ptr; + } + break; + case 2: + { + OPJ_INT16 * l_dest_ptr = (OPJ_INT16 *) p_data; + if + (l_img_comp->sgnd) + { + for + (j=0;j<l_height;++j) + { + for + (k=0;k<l_width;++k) + { + *(l_dest_ptr++) = (OPJ_INT16) (*(l_src_ptr++)); + } + l_src_ptr += l_stride; + } + } + else + { + for + (j=0;j<l_height;++j) + { + for + (k=0;k<l_width;++k) + { + *(l_dest_ptr++) = (*(l_src_ptr++))&0xffff; + } + l_src_ptr += l_stride; + } + } + p_data = (OPJ_BYTE*) l_dest_ptr; + } + break; + case 4: + { + OPJ_INT32 * l_dest_ptr = (OPJ_INT32 *) p_data; + for + (j=0;j<l_height;++j) + { + for + (k=0;k<l_width;++k) + { + *(l_dest_ptr++) = *(l_src_ptr++); + } + l_src_ptr += l_stride; + } + p_data = (OPJ_BYTE*) l_dest_ptr; + } + break; + } + ++l_img_comp; + ++l_tilec; + } +} +bool j2k_update_image_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data) +{ + OPJ_UINT32 i,j,k = 0; + OPJ_UINT32 l_width,l_height,l_offset_x,l_offset_y; + opj_image_comp_t * l_img_comp = 00; + opj_tcd_tilecomp_t * l_tilec = 00; + opj_image_t * l_image = 00; + OPJ_UINT32 l_size_comp, l_remaining; + OPJ_UINT32 l_dest_stride; + OPJ_INT32 * l_dest_ptr; + opj_tcd_resolution_t* l_res= 00; + + + l_tilec = p_tcd->tcd_image->tiles->comps; + l_image = p_tcd->image; + l_img_comp = l_image->comps; + for + (i=0;i<p_tcd->image->numcomps;++i) + { + if + (!l_img_comp->data) + { + l_img_comp->data = (OPJ_INT32*) opj_malloc(l_img_comp->w * l_img_comp->h * sizeof(OPJ_INT32)); + if + (! l_img_comp->data) + { + return false; + } + memset(l_img_comp->data,0,l_img_comp->w * l_img_comp->h * sizeof(OPJ_INT32)); + } + 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; + + if + (l_remaining) + { + ++l_size_comp; + } + if + (l_size_comp == 3) + { + l_size_comp = 4; + } + l_width = (l_res->x1 - l_res->x0); + l_height = (l_res->y1 - l_res->y0); + l_dest_stride = (l_img_comp->w) - l_width; + l_offset_x = int_ceildivpow2(l_img_comp->x0, l_img_comp->factor); + l_offset_y = int_ceildivpow2(l_img_comp->y0, l_img_comp->factor); + l_dest_ptr = l_img_comp->data + (l_res->x0 - l_offset_x) + (l_res->y0 - l_offset_y) * l_img_comp->w; + + switch + (l_size_comp) + { + case 1: + { + OPJ_CHAR * l_src_ptr = (OPJ_CHAR*) p_data; + if + (l_img_comp->sgnd) + { + for + (j=0;j<l_height;++j) + { + for + (k=0;k<l_width;++k) + { + *(l_dest_ptr++) = (OPJ_INT32) (*(l_src_ptr++)); + } + l_dest_ptr += l_dest_stride; + } + + } + else + { + for + (j=0;j<l_height;++j) + { + for + (k=0;k<l_width;++k) + { + *(l_dest_ptr++) = (OPJ_INT32) ((*(l_src_ptr++))&0xff); + } + l_dest_ptr += l_dest_stride; + } + } + p_data = (OPJ_BYTE*) l_src_ptr; + } + break; + case 2: + { + OPJ_INT16 * l_src_ptr = (OPJ_INT16 *) p_data; + if + (l_img_comp->sgnd) + { + for + (j=0;j<l_height;++j) + { + for + (k=0;k<l_width;++k) + { + *(l_dest_ptr++) = *(l_src_ptr++); + } + l_dest_ptr += l_dest_stride; + } + } + else + { + for + (j=0;j<l_height;++j) + { + for + (k=0;k<l_width;++k) + { + *(l_dest_ptr++) = (*(l_src_ptr++))&0xffff; + } + l_dest_ptr += l_dest_stride; + } + } + p_data = (OPJ_BYTE*) l_src_ptr; + } + break; + case 4: + { + OPJ_INT32 * l_src_ptr = (OPJ_INT32 *) p_data; + for + (j=0;j<l_height;++j) + { + for + (k=0;k<l_width;++k) + { + *(l_dest_ptr++) = (*(l_src_ptr++)); + } + l_dest_ptr += l_dest_stride; + } + p_data = (OPJ_BYTE*) l_src_ptr; + } + break; + } + ++l_img_comp; + ++l_tilec; + } + return 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. + */ +bool j2k_set_decode_area( + opj_j2k_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_t * l_cp = &(p_j2k->m_cp); + + if + (p_j2k->m_specific_param.m_decoder.m_state != J2K_DEC_STATE_TPHSOT) + { + return 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 true; +} diff --git a/libopenjpeg/j2k.h b/libopenjpeg/j2k.h index 5599be47..c28123a5 100644 --- a/libopenjpeg/j2k.h +++ b/libopenjpeg/j2k.h @@ -6,6 +6,7 @@ * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe * Copyright (c) 2005, Herve Drolon, FreeImage Team * Copyright (c) 2006-2007, Parvatha Elangovan + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -38,6 +39,11 @@ The functions in J2K.C have for goal to read/write the several parts of the codestream: markers and data. */ +#include "openjpeg.h" + +struct opj_dparameters; +struct opj_stream_private; +struct opj_event_mgr; /** @defgroup J2K J2K - JPEG-2000 codestream reader/writer */ /*@{*/ @@ -77,6 +83,11 @@ 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 */ +#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 */ + /* UniPG>> */ #ifdef USE_JPWL #define J2K_MS_EPC 0xff68 /**< EPC marker value (Part 11: JPEG 2000 for Wireless) */ @@ -97,171 +108,267 @@ The functions in J2K.C have for goal to read/write the several parts of the code Values that specify the status of the decoding process when decoding the main header. These values may be combined with a | operator. */ -typedef enum J2K_STATUS { - J2K_STATE_MHSOC = 0x0001, /**< a SOC marker is expected */ - J2K_STATE_MHSIZ = 0x0002, /**< a SIZ marker is expected */ - J2K_STATE_MH = 0x0004, /**< the decoding process is in the main header */ - J2K_STATE_TPHSOT = 0x0008, /**< the decoding process is in a tile part header and expects a SOT marker */ - J2K_STATE_TPH = 0x0010, /**< the decoding process is in a tile part header */ - J2K_STATE_MT = 0x0020, /**< the EOC marker has just been read */ - J2K_STATE_NEOC = 0x0040, /**< the decoding process must not expect a EOC marker because the codestream is truncated */ - J2K_STATE_ERR = 0x0080 /**< the decoding process has encountered an error */ -} J2K_STATUS; +typedef enum +{ + J2K_DEC_STATE_NONE = 0x0000, /**< a SOC marker is expected */ + J2K_DEC_STATE_MHSOC = 0x0001, /**< a SOC marker is expected */ + J2K_DEC_STATE_MHSIZ = 0x0002, /**< a SIZ marker is expected */ + J2K_DEC_STATE_MH = 0x0004, /**< the decoding process is in the main header */ + J2K_DEC_STATE_TPHSOT = 0x0008, /**< the decoding process is in a tile part header and expects a SOT marker */ + J2K_DEC_STATE_TPH = 0x0010, /**< the decoding process is in a tile part header */ + J2K_DEC_STATE_MT = 0x0020, /**< the EOC marker has just been read */ + J2K_DEC_STATE_NEOC = 0x0040, /**< the decoding process must not expect a EOC marker because the codestream is truncated */ + J2K_DEC_STATE_DATA = 0x0080, /**< the decoding process must not expect a EOC marker because the codestream is truncated */ + J2K_DEC_STATE_ERR = 0x8000, /**< the decoding process has encountered an error */ + J2K_DEC_STATE_EOC = 0x0100 +} +J2K_DECODING_STATUS; -/* ----------------------------------------------------------------------- */ +/** +Values that specify the status of the decoding process when decoding the main header. +These values may be combined with a | operator. +*/ +typedef enum +{ + J2K_ENC_STATE_NONE = 0x0000, /**< a SOC marker is expected */ + J2K_ENC_STATE_ENCODE = 0x0001, /**< a SOC marker is expected */ +} +J2K_ENCODING_STATUS; /** -T2 encoding mode -*/ -typedef enum T2_MODE { - THRESH_CALC = 0, /** Function called in Rate allocation process*/ - FINAL_PASS = 1 /** Function called in Tier 2 process*/ -}J2K_T2_MODE; + * Type of data for storing the MCT data + */ +typedef enum MCT_ELEMENT_TYPE +{ + MCT_TYPE_INT16 = 0, /** MCT data is stored as signed shorts*/ + MCT_TYPE_INT32 = 1, /** MCT data is stored as signed integers*/ + MCT_TYPE_FLOAT = 2, /** MCT data is stored as floats*/ + MCT_TYPE_DOUBLE = 3 /** MCT data is stored as doubles*/ +} J2K_MCT_ELEMENT_TYPE; + +/** + * Type of data for storing the MCT data + */ +typedef enum MCT_ARRAY_TYPE +{ + MCT_TYPE_DEPENDENCY = 0, + MCT_TYPE_DECORRELATION = 1, + MCT_TYPE_OFFSET = 2 +} J2K_MCT_ARRAY_TYPE; + + +/* ----------------------------------------------------------------------- */ + + /** Quantization stepsize */ -typedef struct opj_stepsize { +typedef struct opj_stepsize +{ /** exponent */ - int expn; + OPJ_UINT32 expn; /** mantissa */ - int mant; -} opj_stepsize_t; + OPJ_UINT32 mant; +} +opj_stepsize_t; + +typedef struct opj_mct_data +{ + J2K_MCT_ELEMENT_TYPE m_element_type; + J2K_MCT_ARRAY_TYPE m_array_type; + OPJ_UINT32 m_index; + OPJ_BYTE * m_data; + OPJ_UINT32 m_data_size; +} +opj_mct_data_t; + +typedef struct opj_simple_mcc_decorrelation_data +{ + OPJ_UINT32 m_index; + OPJ_UINT32 m_nb_comps; + opj_mct_data_t * m_decorrelation_array; + opj_mct_data_t * m_offset_array; + OPJ_UINT32 m_is_irreversible : 1; +} +opj_simple_mcc_decorrelation_data_t; + /** Tile-component coding parameters */ -typedef struct opj_tccp { +typedef struct opj_tccp +{ /** coding style */ - int csty; + OPJ_UINT32 csty; /** number of resolutions */ - int numresolutions; + OPJ_UINT32 numresolutions; /** code-blocks width */ - int cblkw; + OPJ_UINT32 cblkw; /** code-blocks height */ - int cblkh; + OPJ_UINT32 cblkh; /** code-block coding style */ - int cblksty; + OPJ_UINT32 cblksty; /** discrete wavelet transform identifier */ - int qmfbid; + OPJ_UINT32 qmfbid; /** quantisation style */ - int qntsty; + OPJ_UINT32 qntsty; /** stepsizes used for quantization */ opj_stepsize_t stepsizes[J2K_MAXBANDS]; /** number of guard bits */ - int numgbits; + OPJ_UINT32 numgbits; /** Region Of Interest shift */ - int roishift; + OPJ_INT32 roishift; /** precinct width */ - int prcw[J2K_MAXRLVLS]; + OPJ_UINT32 prcw[J2K_MAXRLVLS]; /** precinct height */ - int prch[J2K_MAXRLVLS]; -} opj_tccp_t; + OPJ_UINT32 prch[J2K_MAXRLVLS]; + /** the dc_level_shift **/ + OPJ_INT32 m_dc_level_shift; +} +opj_tccp_t; /** Tile coding parameters : this structure is used to store coding/decoding parameters common to all tiles (information like COD, COC in main header) */ -typedef struct opj_tcp { - /** 1 : first part-tile of a tile */ - int first; +typedef struct opj_tcp +{ /** coding style */ - int csty; + OPJ_UINT32 csty; /** progression order */ OPJ_PROG_ORDER prg; /** number of layers */ - int numlayers; + OPJ_UINT32 numlayers; + OPJ_UINT32 num_layers_to_decode; /** multi-component transform identifier */ - int mct; + OPJ_UINT32 mct; /** rates of layers */ - float rates[100]; + OPJ_FLOAT32 rates[100]; /** number of progression order changes */ - int numpocs; - /** indicates if a POC marker has been used O:NO, 1:YES */ - int POC; + OPJ_UINT32 numpocs; /** progression order changes */ opj_poc_t pocs[32]; /** packet header store there for futur use in t2_decode_packet */ - unsigned char *ppt_data; - /** pointer remaining on the first byte of the first header if ppt is used */ - unsigned char *ppt_data_first; - /** If ppt == 1 --> there was a PPT marker for the present tile */ - int ppt; - /** used in case of multiple marker PPT (number of info already stored) */ - int ppt_store; - /** ppmbug1 */ - int ppt_len; + OPJ_BYTE *ppt_data; + /** used to keep a track of the allocated memory */ + OPJ_BYTE *ppt_buffer; + /** Number of bytes stored inside ppt_data*/ + OPJ_UINT32 ppt_data_size; + /** size of ppt_data*/ + OPJ_UINT32 ppt_len; /** add fixed_quality */ - float distoratio[100]; + OPJ_FLOAT32 distoratio[100]; /** tile-component coding parameters */ opj_tccp_t *tccps; + /** number of tile parts for the tile. */ + OPJ_UINT32 m_nb_tile_parts; + /** data for the tile */ + OPJ_BYTE * m_data; + /** size of data */ + OPJ_UINT32 m_data_size; + /** encoding norms */ + OPJ_FLOAT64 * mct_norms; + /** the mct decoding matrix */ + OPJ_FLOAT32 * m_mct_decoding_matrix; + /** the mct coding matrix */ + OPJ_FLOAT32 * m_mct_coding_matrix; + /** mct records */ + opj_mct_data_t * m_mct_records; + /** the number of mct records. */ + OPJ_UINT32 m_nb_mct_records; + /** the max number of mct records. */ + OPJ_UINT32 m_nb_max_mct_records; + /** mcc records */ + opj_simple_mcc_decorrelation_data_t * m_mcc_records; + /** the number of mct records. */ + OPJ_UINT32 m_nb_mcc_records; + /** the max number of mct records. */ + OPJ_UINT32 m_nb_max_mcc_records; + + + + /***** FLAGS *******/ + /** If ppt == 1 --> 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_t; -/** -Coding parameters -*/ -typedef struct opj_cp { +typedef struct opj_encoding_param +{ /** Digital cinema profile*/ - OPJ_CINEMA_MODE cinema; + OPJ_CINEMA_MODE m_cinema; /** Maximum rate for each component. If == 0, component size limitation is not considered */ - int max_comp_size; - /** Size of the image in bits*/ - int img_size; - /** Rsiz*/ - OPJ_RSIZ_CAPABILITIES rsiz; - /** Enabling Tile part generation*/ - char tp_on; - /** Flag determining tile part generation*/ - char tp_flag; + OPJ_UINT32 m_max_comp_size; /** Position of tile part flag in progression order*/ - int tp_pos; + OPJ_INT32 m_tp_pos; + /** fixed layer */ + OPJ_INT32 *m_matrice; + /** Flag determining tile part generation*/ + OPJ_BYTE m_tp_flag; /** allocation by rate/distortion */ - int disto_alloc; + OPJ_UINT32 m_disto_alloc : 1; /** allocation by fixed layer */ - int fixed_alloc; + OPJ_UINT32 m_fixed_alloc : 1; /** add fixed_quality */ - int fixed_quality; + OPJ_UINT32 m_fixed_quality : 1; + /** Enabling Tile part generation*/ + OPJ_UINT32 m_tp_on : 1; +} +opj_encoding_param_t; + +typedef struct opj_decoding_param +{ /** if != 0, then original dimension divided by 2^(reduce); if == 0 or not used, image is decoded to the full resolution */ - int reduce; + OPJ_UINT32 m_reduce; /** if != 0, then only the first "layer" layers are decoded; if == 0 or not used, all the quality layers are decoded */ - int layer; - /** if == NO_LIMITATION, decode entire codestream; if == LIMIT_TO_MAIN_HEADER then only decode the main header */ - OPJ_LIMIT_DECODING limit_decoding; + OPJ_UINT32 m_layer; +} +opj_decoding_param_t; + +/** +Coding parameters +*/ +typedef struct opj_cp +{ + /** Size of the image in bits*/ + /*int img_size;*/ + /** Rsiz*/ + OPJ_RSIZ_CAPABILITIES rsiz; /** XTOsiz */ - int tx0; + OPJ_INT32 tx0; /** YTOsiz */ - int ty0; + OPJ_INT32 ty0; /** XTsiz */ - int tdx; + OPJ_UINT32 tdx; /** YTsiz */ - int tdy; - /** comment for coding */ - char *comment; + OPJ_UINT32 tdy; + /** comment */ + OPJ_CHAR *comment; /** number of tiles in width */ - int tw; + OPJ_UINT32 tw; /** number of tiles in heigth */ - int th; - /** ID number of the tiles present in the codestream */ - int *tileno; - /** size of the vector tileno */ - int tileno_size; + OPJ_UINT32 th; + /** packet header storage original buffer */ + OPJ_BYTE *ppm_buffer; /** packet header store there for futur use in t2_decode_packet */ - unsigned char *ppm_data; - /** pointer remaining on the first byte of the first header if ppm is used */ - unsigned char *ppm_data_first; - /** if ppm == 1 --> there was a PPM marker for the present tile */ - int ppm; - /** use in case of multiple marker PPM (number of info already store) */ - int ppm_store; - /** use in case of multiple marker PPM (case on non-finished previous info) */ - int ppm_previous; - /** ppmbug1 */ - int ppm_len; + OPJ_BYTE *ppm_data; + /** size of the ppm_data*/ + OPJ_UINT32 ppm_len; + /** Number of bytes actually stored inside the ppm_data */ + OPJ_UINT32 ppm_data_size; /** tile coding parameters */ opj_tcp_t *tcps; - /** fixed layer */ - int *matrice; + union + { + opj_decoding_param_t m_dec; + opj_encoding_param_t m_enc; + } + m_specific_param; + + /* UniPG>> */ #ifdef USE_JPWL /** enables writing of EPC in MH, thus activating JPWL */ @@ -305,90 +412,192 @@ typedef struct opj_cp { /** 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; /* <<UniPG */ } opj_cp_t; -/** -JPEG-2000 codestream reader/writer -*/ -typedef struct opj_j2k { - /** codec context */ - opj_common_ptr cinfo; - +typedef struct opj_j2k_dec +{ /** locate in which part of the codestream the decoder is (main header, tile header, end) */ - int state; - /** number of the tile curently concern by coding/decoding */ - int curtileno; - /** Tile part number*/ - int tp_num; - /** Tilepart number currently coding*/ - int cur_tp_num; - /** Total number of tileparts of the current tile*/ - int *cur_totnum_tp; + OPJ_UINT32 m_state; + /** + * store decoding parameters common to all tiles (information like COD, COC in main header) + */ + opj_tcp_t *m_default_tcp; + OPJ_BYTE *m_header_data; + OPJ_UINT32 m_header_data_size; + /** to tell the tile part length */ + OPJ_UINT32 m_sot_length; + /** Only tiles index in the correct range will be decoded.*/ + OPJ_UINT32 m_start_tile_x; + OPJ_UINT32 m_start_tile_y; + OPJ_UINT32 m_end_tile_x; + OPJ_UINT32 m_end_tile_y; + /** to tell that a tile can be decoded. */ + OPJ_UINT32 m_can_decode : 1; + OPJ_UINT32 m_discard_tiles : 1; + OPJ_UINT32 m_skip_data : 1; + +} opj_j2k_dec_t; + +typedef struct opj_j2k_enc +{ + /** Tile part number, regardless of poc, for each new poc, tp is reset to 1*/ + OPJ_UINT32 m_current_poc_tile_part_number; // tp_num + + /** Tile part number currently coding, taking into account POC. m_current_tile_part_number holds the total number of tile parts while encoding the last tile part.*/ + OPJ_UINT32 m_current_tile_part_number; //cur_tp_num + /** locate the start position of the TLM marker after encoding the tilepart, a jump (in j2k_write_sod) is done to the TLM marker to store the value of its length. */ - int tlm_start; - /** Total num of tile parts in whole image = num tiles* num tileparts in each tile*/ - /** used in TLMmarker*/ - int totnum_tp; - /** - locate the position of the end of the tile in the codestream, - used to detect a truncated codestream (in j2k_read_sod) - */ - unsigned char *eot; + OPJ_SIZE_T m_tlm_start; /** - locate the start position of the SOT marker of the current coded tile: - after encoding the tile, a jump (in j2k_write_sod) is done to the SOT marker to store the value of its length. - */ - int sot_start; - int sod_start; + * Stores the sizes of the tlm. + */ + OPJ_BYTE * m_tlm_sot_offsets_buffer; /** - as the J2K-file is written in several parts during encoding, - it enables to make the right correction in position return by cio_tell - */ - int pos_correction; - /** array used to store the data of each tile */ - unsigned char **tile_data; - /** array used to store the length of each tile */ - int *tile_len; - /** - decompression only : - store decoding parameters common to all tiles (information like COD, COC in main header) - */ - opj_tcp_t *default_tcp; + * The current offset of the tlm buffer. + */ + OPJ_BYTE * m_tlm_sot_offsets_current; + + /** Total num of tile parts in whole image = num tiles* num tileparts in each tile*/ + /** used in TLMmarker*/ + OPJ_UINT32 m_total_tile_parts; // totnum_tp + + /* encoded data for a tile */ + OPJ_BYTE * m_encoded_tile_data; + + /* size of the encoded_data */ + OPJ_UINT32 m_encoded_tile_size; + + /* encoded data for a tile */ + OPJ_BYTE * m_header_tile_data; + + /* size of the encoded_data */ + OPJ_UINT32 m_header_tile_data_size; + + +} opj_j2k_enc_t; + + + + +/** +JPEG-2000 codestream reader/writer +*/ +typedef struct opj_j2k +{ + union + { + opj_j2k_dec_t m_decoder; + opj_j2k_enc_t m_encoder; + } + m_specific_param; + + /** number of the tile curently concern by coding/decoding */ + OPJ_UINT32 m_current_tile_number; + /** pointer to the encoded / decoded image */ - opj_image_t *image; - /** pointer to the coding parameters */ - opj_cp_t *cp; + opj_image_t *m_image; + + /** Coding parameters */ + opj_cp_t m_cp; + + /** the list of procedures to exec **/ + struct opj_procedure_list * m_procedure_list; + + /** the list of validation procedures to follow to make sure the code is valid **/ + struct opj_procedure_list * m_validation_list; + /** helper used to write the index file */ opj_codestream_info_t *cstr_info; - /** pointer to the byte i/o stream */ - opj_cio_t *cio; -} opj_j2k_t; + + /** the current tile coder/decoder **/ + struct opj_tcd * m_tcd; + + OPJ_UINT32 m_is_decoder : 1; + +} +opj_j2k_t; /** @name Exported functions */ /*@{*/ /* ----------------------------------------------------------------------- */ /** -Creates a J2K decompression structure -@param cinfo Codec context info -@return Returns a handle to a J2K decompressor if successful, returns NULL otherwise + * Creates a J2K decompression structure. + * + * @return a handle to a J2K decompressor if successful, NULL otherwise. */ -opj_j2k_t* j2k_create_decompress(opj_common_ptr cinfo); +opj_j2k_t* j2k_create_decompress(); + /** -Destroy a J2K decompressor handle -@param j2k J2K decompressor handle to destroy -*/ -void j2k_destroy_decompress(opj_j2k_t *j2k); + * Destroys a jpeg2000 codec. + * + * @param p_j2k the jpeg20000 structure to destroy. + */ +void j2k_destroy (opj_j2k_t *p_j2k); + /** -Setup the decoder decoding parameters using user parameters. -Decoding parameters are returned in j2k->cp. -@param j2k J2K decompressor handle -@param parameters decompression parameters + * Starts a compression scheme, i.e. validates the codec parameters, writes the header. + * + * @param p_j2k the jpeg2000 codec. + * @param cio the stream object. + * @param p_manager the user event manager. + * + * @return true if the codec is valid. + */ +bool j2k_start_compress( + opj_j2k_t *p_j2k, + struct opj_stream_private *cio, + struct opj_image * p_image, + struct opj_event_mgr * p_manager + ); +/** + * Ends the compression procedures and possibiliy add data to be read after the + * codestream. + */ +bool j2k_end_compress(opj_j2k_t *p_j2k, struct opj_stream_private *cio, struct opj_event_mgr * p_manager); + +/** + * Sets up the decoder decoding parameters using user parameters. + * Decoding parameters are stored in j2k->cp. + * + * @param p_j2k J2K codec + * @param p_parameters decompression parameters + * @deprecated */ -void j2k_setup_decoder(opj_j2k_t *j2k, opj_dparameters_t *parameters); +void j2k_setup_decoder( + opj_j2k_t *p_j2k, + struct opj_dparameters *p_parameters + ); +/** + * Reads a jpeg2000 codestream header structure. + * + * @param cio 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. + */ +bool j2k_read_header( + opj_j2k_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, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager + ); /** Decode an image from a JPEG-2000 codestream @param j2k J2K decompressor handle @@ -396,7 +605,14 @@ Decode an image from a JPEG-2000 codestream @param cstr_info Codestream information structure if required, NULL otherwise @return Returns a decoded image if successful, returns NULL otherwise */ -opj_image_t* j2k_decode(opj_j2k_t *j2k, opj_cio_t *cio, opj_codestream_info_t *cstr_info); +opj_image_t* j2k_decode(opj_j2k_t *j2k, struct opj_stream_private *cio, struct opj_event_mgr * p_manager); + +/** + * Ends the decompression procedures and possibiliy add data to be read after the + * codestream. + */ +bool j2k_end_decompress(opj_j2k_t *j2k, struct opj_stream_private *cio, struct opj_event_mgr * p_manager); + /** Decode an image form a JPT-stream (JPEG 2000, JPIP) @param j2k J2K decompressor handle @@ -404,18 +620,15 @@ Decode an image form a JPT-stream (JPEG 2000, JPIP) @param cstr_info Codestream information structure if required, NULL otherwise @return Returns a decoded image if successful, returns NULL otherwise */ -opj_image_t* j2k_decode_jpt_stream(opj_j2k_t *j2k, opj_cio_t *cio, opj_codestream_info_t *cstr_info); +opj_image_t* j2k_decode_jpt_stream(opj_j2k_t *j2k, struct opj_stream_private *cio, struct opj_codestream_info *cstr_info); + /** Creates a J2K compression structure @param cinfo Codec context info @return Returns a handle to a J2K compressor if successful, returns NULL otherwise */ -opj_j2k_t* j2k_create_compress(opj_common_ptr cinfo); -/** -Destroy a J2K compressor handle -@param j2k J2K compressor handle to destroy -*/ -void j2k_destroy_compress(opj_j2k_t *j2k); +opj_j2k_t* j2k_create_compress(); + /** Setup the encoder parameters using the current image and using user parameters. Coding parameters are returned in j2k->cp. @@ -423,20 +636,97 @@ Coding parameters are returned in j2k->cp. @param parameters compression parameters @param image input filled image */ -void j2k_setup_encoder(opj_j2k_t *j2k, opj_cparameters_t *parameters, opj_image_t *image); +void j2k_setup_encoder(opj_j2k_t *j2k, opj_cparameters_t *parameters, opj_image_t *image, struct opj_event_mgr * p_manager); + /** -Converts an enum type progression order to string type -*/ -char *j2k_convert_progression_order(OPJ_PROG_ORDER prg_order); + * Writes a tile. + * @param p_j2k the jpeg2000 codec. + * @param p_stream the stream to write data to. + * @param p_manager the user event manager. + */ +bool j2k_write_tile ( + opj_j2k_t * p_j2k, + OPJ_UINT32 p_tile_index, + OPJ_BYTE * p_data, + OPJ_UINT32 p_data_size, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); + /** -Encode an image into a JPEG-2000 codestream -@param j2k J2K compressor handle -@param cio Output buffer stream -@param image Image to encode -@param cstr_info Codestream information structure if required, NULL otherwise -@return Returns true if successful, returns false otherwise -*/ -bool j2k_encode(opj_j2k_t *j2k, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info); + * Converts an enum type progression order to string type. + * + * @param prg_order the progression order to get. + * + * @return the string representation of the gicen progression order. + */ +const char * j2k_convert_progression_order(OPJ_PROG_ORDER prg_order); + + +/** + * Encodes an image into a JPEG-2000 codestream + */ +bool j2k_encode( + opj_j2k_t * p_j2k, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager + ); +bool j2k_setup_mct_encoding (opj_tcp_t * p_tcp,opj_image_t * p_image); + +/** + * Decode tile data. + * @param p_j2k the jpeg2000 codec. + * @param p_stream the stream to write data to. + * @param p_manager the user event manager. + */ +bool j2k_decode_tile ( + opj_j2k_t * p_j2k, + OPJ_UINT32 p_tile_index, + OPJ_BYTE * p_data, + OPJ_UINT32 p_data_size, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); +/** + * 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. + */ +bool j2k_read_tile_header ( + opj_j2k_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, + bool * p_go_on, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); +/** + * 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. + */ +bool j2k_set_decode_area( + opj_j2k_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 + ); + /* ----------------------------------------------------------------------- */ /*@}*/ diff --git a/libopenjpeg/j2k_lib.c b/libopenjpeg/j2k_lib.c index 91aee007..3b86c728 100644 --- a/libopenjpeg/j2k_lib.c +++ b/libopenjpeg/j2k_lib.c @@ -27,13 +27,16 @@ #ifdef WIN32 #include <windows.h> #else -#include <sys/time.h> +/*#include <sys/time.h> #include <sys/resource.h> #include <sys/times.h> +*/ #endif /* WIN32 */ -#include "opj_includes.h" +#include "j2k_lib.h" -double opj_clock(void) { + +OPJ_FLOAT64 opj_clock(void) { +#if 0 #ifdef WIN32 /* WIN32: use QueryPerformance (very accurate) */ LARGE_INTEGER freq , t ; @@ -55,5 +58,8 @@ double opj_clock(void) { /* (2b) More precisely! Get the microseconds part ! */ return ( procTime + (t.ru_utime.tv_usec + t.ru_stime.tv_usec) * 1e-6 ) ; #endif + +#endif + return 0; } diff --git a/libopenjpeg/j2k_lib.h b/libopenjpeg/j2k_lib.h index 7df4d367..c78c4f21 100644 --- a/libopenjpeg/j2k_lib.h +++ b/libopenjpeg/j2k_lib.h @@ -31,7 +31,7 @@ The functions in J2K_LIB.C are internal utilities mainly used for timing. */ - +#include "openjpeg.h" /** @defgroup MISC MISC - Miscellaneous internal functions */ /*@{*/ @@ -43,7 +43,7 @@ The functions in J2K_LIB.C are internal utilities mainly used for timing. Difference in successive opj_clock() calls tells you the elapsed time @return Returns time in seconds */ -double opj_clock(void); +OPJ_FLOAT64 opj_clock(void); /* ----------------------------------------------------------------------- */ /*@}*/ diff --git a/libopenjpeg/jp2.c b/libopenjpeg/jp2.c index b2831cfb..1bd7b4a9 100644 --- a/libopenjpeg/jp2.c +++ b/libopenjpeg/jp2.c @@ -5,6 +5,7 @@ * Copyright (c) 2002-2003, Yannick Verschueren * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,540 +29,2052 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ - -#include "opj_includes.h" +#include "jp2.h" +#include "cio.h" +#include "opj_malloc.h" +#include "event.h" +#include "j2k.h" +#include "function_list.h" +#include "assert.h" /** @defgroup JP2 JP2 - JPEG-2000 file format reader/writer */ /*@{*/ +#define BOX_SIZE 1024 + + + /** @name Local static functions */ /*@{*/ + + /** -Read box headers -@param cinfo Codec context info -@param cio Input stream -@param box -@return Returns true if successful, returns false otherwise + * Writes the Jpeg2000 file Header box - JP2 Header box (warning, this is a super box). + * + * @param cio the stream to write data to. + * @param jp2 the jpeg2000 file codec. + * @param p_manager user event manager. + * + * @return true if writting was successful. */ -static bool jp2_read_boxhdr(opj_common_ptr cinfo, opj_cio_t *cio, opj_jp2_box_t *box); -/*static void jp2_write_url(opj_cio_t *cio, char *Idx_file);*/ +bool jp2_write_jp2h( + opj_jp2_t *jp2, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager + ); + /** -Read the IHDR box - Image Header box -@param jp2 JP2 handle -@param cio Input buffer stream -@return Returns true if successful, returns false otherwise -*/ -static bool jp2_read_ihdr(opj_jp2_t *jp2, opj_cio_t *cio); -static void jp2_write_ihdr(opj_jp2_t *jp2, opj_cio_t *cio); -static void jp2_write_bpcc(opj_jp2_t *jp2, opj_cio_t *cio); -static bool jp2_read_bpcc(opj_jp2_t *jp2, opj_cio_t *cio); -static void jp2_write_colr(opj_jp2_t *jp2, opj_cio_t *cio); -static bool jp2_read_colr(opj_jp2_t *jp2, opj_cio_t *cio); -/** -Write the FTYP box - File type box -@param jp2 JP2 handle -@param cio Output buffer stream + * Skips the Jpeg2000 Codestream Header box - JP2C Header box. + * + * @param cio the stream to write data to. + * @param jp2 the jpeg2000 file codec. + * @param p_manager user event manager. + * + * @return true if writting was successful. */ -static void jp2_write_ftyp(opj_jp2_t *jp2, opj_cio_t *cio); +bool jp2_skip_jp2c( + opj_jp2_t *jp2, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager + ); + /** -Read the FTYP box - File type box -@param jp2 JP2 handle -@param cio Input buffer stream -@return Returns true if successful, returns false otherwise + * Reads the Jpeg2000 file Header box - JP2 Header box (warning, this is a super box). + * + * @param p_header_data the data contained in the file header box. + * @param jp2 the jpeg2000 file codec. + * @param p_header_size the size of the data contained in the file header box. + * @param p_manager the user event manager. + * + * @return true if the JP2 Header box was successfully reconized. */ -static bool jp2_read_ftyp(opj_jp2_t *jp2, opj_cio_t *cio); -static int jp2_write_jp2c(opj_jp2_t *jp2, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info); -static bool jp2_read_jp2c(opj_jp2_t *jp2, opj_cio_t *cio, unsigned int *j2k_codestream_length, unsigned int *j2k_codestream_offset); -static void jp2_write_jp(opj_cio_t *cio); -/** -Read the JP box - JPEG 2000 signature -@param jp2 JP2 handle -@param cio Input buffer stream -@return Returns true if successful, returns false otherwise +bool jp2_read_jp2h( + opj_jp2_t *jp2, + unsigned char * p_header_data, + unsigned int p_header_size, + struct opj_event_mgr * p_manager + ); + +/** + * Writes the Jpeg2000 codestream Header box - JP2C Header box. This function must be called AFTER the coding has been done. + * + * @param cio the stream to write data to. + * @param jp2 the jpeg2000 file codec. + * @param p_manager user event manager. + * + * @return true if writting was successful. */ -static bool jp2_read_jp(opj_jp2_t *jp2, opj_cio_t *cio); +static bool jp2_write_jp2c( + opj_jp2_t *jp2, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager + ); + /** -Decode the structure of a JP2 file -@param jp2 JP2 handle -@param cio Input buffer stream -@return Returns true if successful, returns false otherwise + * Reads a box header. The box is the way data is packed inside a jpeg2000 file structure. + * + * @param cio the input stream to read data from. + * @param box the box structure to fill. + * @param p_number_bytes_read pointer to an int that will store the number of bytes read from the stream (shoul usually be 2). + * @param p_manager user event manager. + * + * @return true if the box is reconized, false otherwise */ -static bool jp2_read_struct(opj_jp2_t *jp2, opj_cio_t *cio); +static bool jp2_read_boxhdr( + opj_jp2_box_t *box, + OPJ_UINT32 * p_number_bytes_read, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager + ); -/*@}*/ +/** + * Reads a box header. The box is the way data is packed inside a jpeg2000 file structure. Data is read from a character string + * + * @param p_data the character string to read data from. + * @param box the box structure to fill. + * @param p_number_bytes_read pointer to an int that will store the number of bytes read from the stream (shoul usually be 2). + * @param p_box_max_size the maximum number of bytes in the box. + * + * @return true if the box is reconized, false otherwise +*/ +static bool jp2_read_boxhdr_char( + opj_jp2_box_t *box, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_number_bytes_read, + OPJ_UINT32 p_box_max_size, + struct opj_event_mgr * p_manager + ); -/*@}*/ +/** + * Reads a jpeg2000 file signature box. + * + * @param p_header_data the data contained in the signature box. + * @param jp2 the jpeg2000 file codec. + * @param p_header_size the size of the data contained in the signature box. + * @param p_manager the user event manager. + * + * @return true if the file signature box is valid. + */ +static bool jp2_read_jp( + opj_jp2_t *jp2, + unsigned char * p_header_data, + unsigned int p_header_size, + struct opj_event_mgr * p_manager + ); -/* ----------------------------------------------------------------------- */ +/** + * Writes a jpeg2000 file signature box. + * + * @param cio the stream to write data to. + * @param jp2 the jpeg2000 file codec. + * @param p_manager the user event manager. + * + * @return true if writting was successful. + */ +static bool jp2_write_jp( + opj_jp2_t *jp2, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager + ); -static bool jp2_read_boxhdr(opj_common_ptr cinfo, opj_cio_t *cio, opj_jp2_box_t *box) { - box->init_pos = cio_tell(cio); - box->length = cio_read(cio, 4); - box->type = cio_read(cio, 4); - if (box->length == 1) { - if (cio_read(cio, 4) != 0) { - opj_event_msg(cinfo, EVT_ERROR, "Cannot handle box sizes higher than 2^32\n"); - return false; - } - box->length = cio_read(cio, 4); - if (box->length == 0) - box->length = cio_numbytesleft(cio) + 12; - } - else if (box->length == 0) { - box->length = cio_numbytesleft(cio) + 8; - } - - return true; -} +/** + * Writes a FTYP box - File type box + * + * @param cio the stream to write data to. + * @param jp2 the jpeg2000 file codec. + * @param p_manager the user event manager. + * + * @return true if writting was successful. + */ +static bool jp2_write_ftyp( + opj_jp2_t *jp2, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager + ); -#if 0 -static void jp2_write_url(opj_cio_t *cio, char *Idx_file) { - unsigned int i; - opj_jp2_box_t box; +/** + * Reads a a FTYP box - File type box + * + * @param p_header_data the data contained in the FTYP box. + * @param jp2 the jpeg2000 file codec. + * @param p_header_size the size of the data contained in the FTYP box. + * @param p_manager the user event manager. + * + * @return true if the FTYP box is valid. + */ +static bool jp2_read_ftyp( + opj_jp2_t *jp2, + unsigned char * p_header_data, + unsigned int p_header_size, + struct opj_event_mgr * p_manager + ); - box.init_pos = cio_tell(cio); - cio_skip(cio, 4); - cio_write(cio, JP2_URL, 4); /* DBTL */ - cio_write(cio, 0, 1); /* VERS */ - cio_write(cio, 0, 3); /* FLAG */ +/** + * Reads a IHDR box - Image Header box + * + * @param p_image_header_data pointer to actual data (already read from file) + * @param jp2 the jpeg2000 file codec. + * @param p_image_header_size the size of the image header + * @param p_manager the user event manager. + * + * @return true if the image header is valid, fale else. + */ +static bool jp2_read_ihdr( + opj_jp2_t *jp2, + unsigned char * p_image_header_data, + unsigned int p_image_header_size, + struct opj_event_mgr * p_manager + ); - if(Idx_file) { - for (i = 0; i < strlen(Idx_file); i++) { - cio_write(cio, Idx_file[i], 1); - } - } +/** + * Writes the Image Header box - Image Header box. + * + * @param jp2 jpeg2000 file codec. + * @param p_nb_bytes_written pointer to store the nb of bytes written by the function. + * + * @return the data being copied. +*/ +static unsigned char * jp2_write_ihdr( + opj_jp2_t *jp2, + unsigned int * p_nb_bytes_written + ); - box.length = cio_tell(cio) - box.init_pos; - cio_seek(cio, box.init_pos); - cio_write(cio, box.length, 4); /* L */ - cio_seek(cio, box.init_pos + box.length); -} -#endif +/** + * Reads a Bit per Component box. + * + * @param p_bpc_header_data pointer to actual data (already read from file) + * @param jp2 the jpeg2000 file codec. + * @param p_bpc_header_size the size of the bpc header + * @param p_manager the user event manager. + * + * @return true if the bpc header is valid, fale else. + */ +static bool jp2_read_bpcc( + opj_jp2_t *jp2, + unsigned char * p_bpc_header_data, + unsigned int p_bpc_header_size, + struct opj_event_mgr * p_manager + ); -static bool jp2_read_ihdr(opj_jp2_t *jp2, opj_cio_t *cio) { - opj_jp2_box_t box; - opj_common_ptr cinfo = jp2->cinfo; +/** + * Writes the Bit per Component box. + * + * @param jp2 jpeg2000 file codec. + * @param p_nb_bytes_written pointer to store the nb of bytes written by the function. + * + * @return the data being copied. +*/ +static unsigned char * jp2_write_bpcc( + opj_jp2_t *jp2, + unsigned int * p_nb_bytes_written + ); - jp2_read_boxhdr(cinfo, cio, &box); - if (JP2_IHDR != box.type) { - opj_event_msg(cinfo, EVT_ERROR, "Expected IHDR Marker\n"); - return false; - } +/** + * Reads the Colour Specification box. + * + * @param p_colr_header_data pointer to actual data (already read from file) + * @param jp2 the jpeg2000 file codec. + * @param p_colr_header_size the size of the color header + * @param p_manager the user event manager. + * + * @return true if the bpc header is valid, fale else. +*/ +static bool jp2_read_colr( + opj_jp2_t *jp2, + unsigned char * p_colr_header_data, + unsigned int p_colr_header_size, + struct opj_event_mgr * p_manager + ); - jp2->h = cio_read(cio, 4); /* HEIGHT */ - jp2->w = cio_read(cio, 4); /* WIDTH */ - jp2->numcomps = cio_read(cio, 2); /* NC */ - jp2->comps = (opj_jp2_comps_t*) opj_malloc(jp2->numcomps * sizeof(opj_jp2_comps_t)); +/** + * Writes the Colour Specification box. + * + * @param jp2 jpeg2000 file codec. + * @param p_nb_bytes_written pointer to store the nb of bytes written by the function. + * + * @return the data being copied. +*/ +static unsigned char *jp2_write_colr( + opj_jp2_t *jp2, + unsigned int * p_nb_bytes_written + ); - jp2->bpc = cio_read(cio, 1); /* BPC */ - jp2->C = cio_read(cio, 1); /* C */ - jp2->UnkC = cio_read(cio, 1); /* UnkC */ - jp2->IPR = cio_read(cio, 1); /* IPR */ +/** + * Reads a jpeg2000 file header structure. + * + * @param cio the stream to read data from. + * @param jp2 the jpeg2000 file header structure. + * @param p_manager the user event manager. + * + * @return true if the box is valid. + */ +bool jp2_read_header_procedure( + opj_jp2_t *jp2, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager + ); +/** + * Excutes the given procedures on the given codec. + * + * @param p_procedure_list the list of procedures to execute + * @param jp2 the jpeg2000 file codec to execute the procedures on. + * @param cio the stream to execute the procedures on. + * @param p_manager the user manager. + * + * @return true if all the procedures were successfully executed. + */ +static bool jp2_exec ( + opj_jp2_t * jp2, + struct opj_procedure_list * p_procedure_list, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager + ); +/** + * Finds the execution function related to the given box id. + * + * @param p_id the id of the handler to fetch. + * + * @return the given handler or NULL if it could not be found. + */ +static const opj_jp2_header_handler_t * jp2_find_handler (int p_id); - if (cio_tell(cio) - box.init_pos != box.length) { - opj_event_msg(cinfo, EVT_ERROR, "Error with IHDR Box\n"); - return false; - } +/** + * 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 jp2_setup_encoding_validation (opj_jp2_t *jp2); - return true; -} +/** + * Sets up the procedures to do on writting header. Developpers wanting to extend the library can add their own writting procedures. + */ +static void jp2_setup_header_writting (opj_jp2_t *jp2); + +/** + * The default validation procedure without any extension. + * + * @param jp2 the jpeg2000 codec to validate. + * @param cio the input stream to validate. + * @param p_manager the user event manager. + * + * @return true if the parameters are correct. + */ +bool jp2_default_validation ( + opj_jp2_t * jp2, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager + ); -static void jp2_write_ihdr(opj_jp2_t *jp2, opj_cio_t *cio) { - opj_jp2_box_t box; +/** + * Finds the execution function related to the given box id. + * + * @param p_id the id of the handler to fetch. + * + * @return the given handler or NULL if it could not be found. + */ +static const opj_jp2_header_handler_t * jp2_find_handler ( + int p_id + ); - box.init_pos = cio_tell(cio); - cio_skip(cio, 4); - cio_write(cio, JP2_IHDR, 4); /* IHDR */ +/** + * Finds the image execution function related to the given box id. + * + * @param p_id the id of the handler to fetch. + * + * @return the given handler or NULL if it could not be found. + */ +static const opj_jp2_header_handler_t * jp2_img_find_handler ( + int p_id + ); - cio_write(cio, jp2->h, 4); /* HEIGHT */ - cio_write(cio, jp2->w, 4); /* WIDTH */ - cio_write(cio, jp2->numcomps, 2); /* NC */ +/** + * Sets up the procedures to do on writting header after the codestream. + * Developpers wanting to extend the library can add their own writting procedures. + */ +static void jp2_setup_end_header_writting (opj_jp2_t *jp2); - cio_write(cio, jp2->bpc, 1); /* BPC */ +/** + * Sets up the procedures to do on reading header after the codestream. + * Developpers wanting to extend the library can add their own writting procedures. + */ +static void jp2_setup_end_header_reading (opj_jp2_t *jp2); - cio_write(cio, jp2->C, 1); /* C : Always 7 */ - cio_write(cio, jp2->UnkC, 1); /* UnkC, colorspace unknown */ - cio_write(cio, jp2->IPR, 1); /* IPR, no intellectual property */ +/** + * 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 jp2_setup_decoding_validation (opj_jp2_t *jp2); - box.length = cio_tell(cio) - box.init_pos; - cio_seek(cio, box.init_pos); - cio_write(cio, box.length, 4); /* L */ - cio_seek(cio, box.init_pos + box.length); -} +/** + * Sets up the procedures to do on reading header. + * Developpers wanting to extend the library can add their own writting procedures. + */ +static void jp2_setup_header_reading (opj_jp2_t *jp2); +/*@}*/ -static void jp2_write_bpcc(opj_jp2_t *jp2, opj_cio_t *cio) { - unsigned int i; - opj_jp2_box_t box; +/*@}*/ - box.init_pos = cio_tell(cio); - cio_skip(cio, 4); - cio_write(cio, JP2_BPCC, 4); /* BPCC */ +/* ----------------------------------------------------------------------- */ +const opj_jp2_header_handler_t jp2_header [] = +{ + {JP2_JP,jp2_read_jp}, + {JP2_FTYP,jp2_read_ftyp}, + {JP2_JP2H,jp2_read_jp2h} +}; + +const opj_jp2_header_handler_t jp2_img_header [] = +{ + {JP2_IHDR,jp2_read_ihdr}, + {JP2_COLR,jp2_read_colr}, + {JP2_BPCC,jp2_read_bpcc} +}; +/** + * Finds the execution function related to the given box id. + * + * @param p_id the id of the handler to fetch. + * + * @return the given handler or 00 if it could not be found. + */ +const opj_jp2_header_handler_t * jp2_find_handler ( + int p_id + ) +{ + unsigned int i, l_handler_size = sizeof(jp2_header) / sizeof(opj_jp2_header_handler_t); + for + (i=0;i<l_handler_size;++i) + { + if + (jp2_header[i].id == p_id) + { + return &jp2_header[i]; + } + } + return 00; +} - for (i = 0; i < jp2->numcomps; i++) { - cio_write(cio, jp2->comps[i].bpcc, 1); +/** + * Finds the image execution function related to the given box id. + * + * @param p_id the id of the handler to fetch. + * + * @return the given handler or 00 if it could not be found. + */ +static const opj_jp2_header_handler_t * jp2_img_find_handler ( + int p_id + ) +{ + unsigned int i, l_handler_size = sizeof(jp2_img_header) / sizeof(opj_jp2_header_handler_t); + for + (i=0;i<l_handler_size;++i) + { + if + (jp2_img_header[i].id == p_id) + { + return &jp2_img_header[i]; + } } + return 00; - box.length = cio_tell(cio) - box.init_pos; - cio_seek(cio, box.init_pos); - cio_write(cio, box.length, 4); /* L */ - cio_seek(cio, box.init_pos + box.length); } - -static bool jp2_read_bpcc(opj_jp2_t *jp2, opj_cio_t *cio) { - unsigned int i; +/** + * Reads a jpeg2000 file header structure. + * + * @param cio the stream to read data from. + * @param jp2 the jpeg2000 file header structure. + * @param p_manager the user event manager. + * + * @return true if the box is valid. + */ +bool jp2_read_header_procedure( + opj_jp2_t *jp2, + opj_stream_private_t *cio, + opj_event_mgr_t * p_manager) +{ opj_jp2_box_t box; - - opj_common_ptr cinfo = jp2->cinfo; - - jp2_read_boxhdr(cinfo, cio, &box); - if (JP2_BPCC != box.type) { - opj_event_msg(cinfo, EVT_ERROR, "Expected BPCC Marker\n"); + unsigned int l_nb_bytes_read; + const opj_jp2_header_handler_t * l_current_handler; + unsigned int l_last_data_size = BOX_SIZE; + unsigned int l_current_data_size; + unsigned char * l_current_data = 00; + + // preconditions + assert(cio != 00); + assert(jp2 != 00); + assert(p_manager != 00); + + l_current_data = opj_malloc(l_last_data_size); + + if + (l_current_data == 00) + { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to handle jpeg2000 file header\n"); return false; } + memset(l_current_data, 0 , l_last_data_size); + while + (jp2_read_boxhdr(&box,&l_nb_bytes_read,cio,p_manager)) + { + // is it the codestream box ? + if + (box.type == JP2_JP2C) + { + if + (jp2->jp2_state & JP2_STATE_HEADER) + { + jp2->jp2_state |= JP2_STATE_CODESTREAM; + return true; + } + else + { + opj_event_msg(p_manager, EVT_ERROR, "bad placed jpeg codestream\n"); + return false; + } + } + else if + (box.length == 0) + { + opj_event_msg(p_manager, EVT_ERROR, "Cannot handle box of undefined sizes\n"); + return false; + } - for (i = 0; i < jp2->numcomps; i++) { - jp2->comps[i].bpcc = cio_read(cio, 1); + l_current_handler = jp2_find_handler(box.type); + l_current_data_size = box.length - l_nb_bytes_read; + + if + (l_current_handler != 00) + { + if + (l_current_data_size > l_last_data_size) + { + l_current_data = opj_realloc(l_current_data,l_current_data_size); + l_last_data_size = l_current_data_size; + } + l_nb_bytes_read = opj_stream_read_data(cio,l_current_data,l_current_data_size,p_manager); + if + (l_nb_bytes_read != l_current_data_size) + { + opj_event_msg(p_manager, EVT_ERROR, "Problem with reading JPEG2000 box, stream error\n"); + return false; + } + if + (! l_current_handler->handler(jp2,l_current_data,l_current_data_size,p_manager)) + { + return false; + } + } + else + { + jp2->jp2_state |= JP2_STATE_UNKNOWN; + if + (opj_stream_skip(cio,l_current_data_size,p_manager) != l_current_data_size) + { + opj_event_msg(p_manager, EVT_ERROR, "Problem with skipping JPEG2000 box, stream error\n"); + return false; + } + } } + return true; +} - if (cio_tell(cio) - box.init_pos != box.length) { - opj_event_msg(cinfo, EVT_ERROR, "Error with BPCC Box\n"); +/** + * Reads a box header. The box is the way data is packed inside a jpeg2000 file structure. + * + * @param cio the input stream to read data from. + * @param box the box structure to fill. + * @param p_number_bytes_read pointer to an int that will store the number of bytes read from the stream (should usually be 8). + * @param p_manager user event manager. + * + * @return true if the box is reconized, false otherwise +*/ +bool jp2_read_boxhdr(opj_jp2_box_t *box, OPJ_UINT32 * p_number_bytes_read,opj_stream_private_t *cio, opj_event_mgr_t * p_manager) +{ + /* read header from file */ + unsigned char l_data_header [8]; + + // preconditions + assert(cio != 00); + assert(box != 00); + assert(p_number_bytes_read != 00); + assert(p_manager != 00); + + *p_number_bytes_read = opj_stream_read_data(cio,l_data_header,8,p_manager); + if + (*p_number_bytes_read != 8) + { return false; } - + /* process read data */ + opj_read_bytes(l_data_header,&(box->length), 4); + opj_read_bytes(l_data_header+4,&(box->type), 4); + + // do we have a "special very large box ?" + // read then the XLBox + if + (box->length == 1) + { + OPJ_UINT32 l_xl_part_size; + OPJ_UINT32 l_nb_bytes_read = opj_stream_read_data(cio,l_data_header,8,p_manager); + if + (l_nb_bytes_read != 8) + { + if + (l_nb_bytes_read > 0) + { + *p_number_bytes_read += l_nb_bytes_read; + } + return false; + } + opj_read_bytes(l_data_header,&l_xl_part_size, 4); + if + (l_xl_part_size != 0) + { + opj_event_msg(p_manager, EVT_ERROR, "Cannot handle box sizes higher than 2^32\n"); + return false; + } + opj_read_bytes(l_data_header,&(box->length), 4); + } return true; } -static void jp2_write_colr(opj_jp2_t *jp2, opj_cio_t *cio) { - opj_jp2_box_t box; +/** + * Reads a box header. The box is the way data is packed inside a jpeg2000 file structure. Data is read from a character string + * + * @param p_data the character string to read data from. + * @param box the box structure to fill. + * @param p_number_bytes_read pointer to an int that will store the number of bytes read from the stream (shoul usually be 2). + * @param p_box_max_size the maximum number of bytes in the box. + * + * @return true if the box is reconized, false otherwise +*/ +static bool jp2_read_boxhdr_char( + opj_jp2_box_t *box, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_number_bytes_read, + OPJ_UINT32 p_box_max_size, + opj_event_mgr_t * p_manager + ) +{ + // preconditions + assert(p_data != 00); + assert(box != 00); + assert(p_number_bytes_read != 00); + assert(p_manager != 00); + + if + (p_box_max_size < 8) + { + opj_event_msg(p_manager, EVT_ERROR, "Cannot handle box of less than 8 bytes\n"); + return false; + } + /* process read data */ + opj_read_bytes(p_data,&(box->length), 4); + p_data += 4; + opj_read_bytes(p_data,&(box->type), 4); + p_data += 4; + *p_number_bytes_read = 8; + + // do we have a "special very large box ?" + // read then the XLBox + if + (box->length == 1) + { + unsigned int l_xl_part_size; + if + (p_box_max_size < 16) + { + opj_event_msg(p_manager, EVT_ERROR, "Cannot handle XL box of less than 16 bytes\n"); + return false; + } - box.init_pos = cio_tell(cio); - cio_skip(cio, 4); - cio_write(cio, JP2_COLR, 4); /* COLR */ + opj_read_bytes(p_data,&l_xl_part_size, 4); + p_data += 4; + *p_number_bytes_read += 4; + if + (l_xl_part_size != 0) + { + opj_event_msg(p_manager, EVT_ERROR, "Cannot handle box sizes higher than 2^32\n"); + return false; + } + opj_read_bytes(p_data,&(box->length), 4); + *p_number_bytes_read += 4; + if + (box->length == 0) + { + opj_event_msg(p_manager, EVT_ERROR, "Cannot handle box of undefined sizes\n"); + return false; + } + + } + else if + (box->length == 0) + { + opj_event_msg(p_manager, EVT_ERROR, "Cannot handle box of undefined sizes\n"); + return false; + } + return true; +} - cio_write(cio, jp2->meth, 1); /* METH */ - cio_write(cio, jp2->precedence, 1); /* PRECEDENCE */ - cio_write(cio, jp2->approx, 1); /* APPROX */ - if (jp2->meth == 1) { - cio_write(cio, jp2->enumcs, 4); /* EnumCS */ - } else { - cio_write(cio, 0, 1); /* PROFILE (??) */ +/** + * Reads a jpeg2000 file signature box. + * + * @param p_header_data the data contained in the signature box. + * @param jp2 the jpeg2000 file codec. + * @param p_header_size the size of the data contained in the signature box. + * @param p_manager the user event manager. + * + * @return true if the file signature box is valid. + */ +bool jp2_read_jp( + opj_jp2_t *jp2, + unsigned char * p_header_data, + unsigned int p_header_size, + opj_event_mgr_t * p_manager + ) +{ + unsigned int l_magic_number; + + // preconditions + assert(p_header_data != 00); + assert(jp2 != 00); + assert(p_manager != 00); + + if + (jp2->jp2_state != JP2_STATE_NONE) + { + opj_event_msg(p_manager, EVT_ERROR, "The signature box must be the first box in the file.\n"); + return false; } + - box.length = cio_tell(cio) - box.init_pos; - cio_seek(cio, box.init_pos); - cio_write(cio, box.length, 4); /* L */ - cio_seek(cio, box.init_pos + box.length); + /* assure length of data is correct (4 -> magic number) */ + if + (p_header_size != 4) + { + opj_event_msg(p_manager, EVT_ERROR, "Error with JP signature Box size\n"); + return false; + } + + // rearrange data + opj_read_bytes(p_header_data,&l_magic_number,4); + if + (l_magic_number != 0x0d0a870a ) + { + opj_event_msg(p_manager, EVT_ERROR, "Error with JP Signature : bad magic number\n"); + return false; + } + jp2->jp2_state |= JP2_STATE_SIGNATURE; + return true; } -static bool jp2_read_colr(opj_jp2_t *jp2, opj_cio_t *cio) { - opj_jp2_box_t box; - int skip_len; +/** + * Reads a a FTYP box - File type box + * + * @param p_header_data the data contained in the FTYP box. + * @param jp2 the jpeg2000 file codec. + * @param p_header_size the size of the data contained in the FTYP box. + * @param p_manager the user event manager. + * + * @return true if the FTYP box is valid. + */ +bool jp2_read_ftyp( + opj_jp2_t *jp2, + unsigned char * p_header_data, + unsigned int p_header_size, + opj_event_mgr_t * p_manager + ) +{ + unsigned int i; + unsigned int l_remaining_bytes; - opj_common_ptr cinfo = jp2->cinfo; + // preconditions + assert(p_header_data != 00); + assert(jp2 != 00); + assert(p_manager != 00); - jp2_read_boxhdr(cinfo, cio, &box); - do { - if (JP2_COLR != box.type) { - cio_skip(cio, box.length - 8); - jp2_read_boxhdr(cinfo, cio, &box); - } - } while(JP2_COLR != box.type); + if + (jp2->jp2_state != JP2_STATE_SIGNATURE) + { + opj_event_msg(p_manager, EVT_ERROR, "The ftyp box must be the second box in the file.\n"); + return false; + } + + /* assure length of data is correct */ + if + (p_header_size < 8) + { + opj_event_msg(p_manager, EVT_ERROR, "Error with FTYP signature Box size\n"); + return false; + } + + opj_read_bytes(p_header_data,&jp2->brand,4); /* BR */ + p_header_data += 4; - jp2->meth = cio_read(cio, 1); /* METH */ - jp2->precedence = cio_read(cio, 1); /* PRECEDENCE */ - jp2->approx = cio_read(cio, 1); /* APPROX */ + opj_read_bytes(p_header_data,&jp2->minversion,4); /* MinV */ + p_header_data += 4; + + l_remaining_bytes = p_header_size - 8; - if (jp2->meth == 1) { - jp2->enumcs = cio_read(cio, 4); /* EnumCS */ - } else { - /* skip PROFILE */ - skip_len = box.init_pos + box.length - cio_tell(cio); - if (skip_len < 0) { - opj_event_msg(cinfo, EVT_ERROR, "Error with JP2H box size\n"); + /* the number of remaining bytes should be a multiple of 4 */ + if + ((l_remaining_bytes & 0x3) != 0) + { + opj_event_msg(p_manager, EVT_ERROR, "Error with FTYP signature Box size\n"); + return false; + } + /* div by 4 */ + jp2->numcl = l_remaining_bytes >> 2; + if + (jp2->numcl) + { + jp2->cl = (unsigned int *) opj_malloc(jp2->numcl * sizeof(unsigned int)); + if + (jp2->cl == 00) + { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory with FTYP Box\n"); return false; } - cio_skip(cio, box.init_pos + box.length - cio_tell(cio)); + memset(jp2->cl,0,jp2->numcl * sizeof(unsigned int)); } - if (cio_tell(cio) - box.init_pos != box.length) { - opj_event_msg(cinfo, EVT_ERROR, "Error with BPCC Box\n"); + + for + (i = 0; i < jp2->numcl; ++i) + { + opj_read_bytes(p_header_data,&jp2->cl[i],4); /* CLi */ + p_header_data += 4; + + } + jp2->jp2_state |= JP2_STATE_FILE_TYPE; + return true; +} + +/** + * Writes a jpeg2000 file signature box. + * + * @param cio the stream to write data to. + * @param jp2 the jpeg2000 file codec. + * @param p_manager the user event manager. + * + * @return true if writting was successful. + */ +bool jp2_write_jp ( + opj_jp2_t *jp2, + opj_stream_private_t *cio, + opj_event_mgr_t * p_manager + ) +{ + /* 12 bytes will be read */ + unsigned char l_signature_data [12]; + + // preconditions + assert(cio != 00); + assert(jp2 != 00); + assert(p_manager != 00); + + + /* write box length */ + opj_write_bytes(l_signature_data,12,4); + /* writes box type */ + opj_write_bytes(l_signature_data+4,JP2_JP,4); + /* writes magic number*/ + opj_write_bytes(l_signature_data+8,0x0d0a870a,4); + if + (opj_stream_write_data(cio,l_signature_data,12,p_manager) != 12) + { return false; } return true; } -void jp2_write_jp2h(opj_jp2_t *jp2, opj_cio_t *cio) { - opj_jp2_box_t box; - box.init_pos = cio_tell(cio); - cio_skip(cio, 4); - cio_write(cio, JP2_JP2H, 4); /* JP2H */ +/** + * Writes a FTYP box - File type box + * + * @param cio the stream to write data to. + * @param jp2 the jpeg2000 file codec. + * @param p_manager the user event manager. + * + * @return true if writting was successful. + */ +bool jp2_write_ftyp( + opj_jp2_t *jp2, + opj_stream_private_t *cio, + opj_event_mgr_t * p_manager + ) +{ + unsigned int i; + unsigned int l_ftyp_size = 16 + 4 * jp2->numcl; + unsigned char * l_ftyp_data, * l_current_data_ptr; + bool l_result; - jp2_write_ihdr(jp2, cio); + // preconditions + assert(cio != 00); + assert(jp2 != 00); + assert(p_manager != 00); - if (jp2->bpc == 255) { - jp2_write_bpcc(jp2, cio); + l_ftyp_data = (unsigned char *) opj_malloc(l_ftyp_size); + + if + (l_ftyp_data == 00) + { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to handle ftyp data\n"); + return false; } - jp2_write_colr(jp2, cio); + memset(l_ftyp_data,0,l_ftyp_size); - box.length = cio_tell(cio) - box.init_pos; - cio_seek(cio, box.init_pos); - cio_write(cio, box.length, 4); /* L */ - cio_seek(cio, box.init_pos + box.length); + l_current_data_ptr = l_ftyp_data; + + opj_write_bytes(l_current_data_ptr, l_ftyp_size,4); /* box size */ + l_current_data_ptr += 4; + + opj_write_bytes(l_current_data_ptr, JP2_FTYP,4); /* FTYP */ + l_current_data_ptr += 4; + + opj_write_bytes(l_current_data_ptr, jp2->brand,4); /* BR */ + l_current_data_ptr += 4; + + opj_write_bytes(l_current_data_ptr, jp2->minversion,4); /* MinV */ + l_current_data_ptr += 4; + + for + (i = 0; i < jp2->numcl; i++) + { + opj_write_bytes(l_current_data_ptr, jp2->cl[i],4); /* CL */ + } + + l_result = (opj_stream_write_data(cio,l_ftyp_data,l_ftyp_size,p_manager) == l_ftyp_size); + if + (! l_result) + { + opj_event_msg(p_manager, EVT_ERROR, "Error while writting ftyp data to stream\n"); + } + opj_free(l_ftyp_data); + return l_result; } -bool jp2_read_jp2h(opj_jp2_t *jp2, opj_cio_t *cio) { - opj_jp2_box_t box; - int skip_len; +/** + * Writes the Jpeg2000 file Header box - JP2 Header box (warning, this is a super box). + * + * @param cio the stream to write data to. + * @param jp2 the jpeg2000 file codec. + * @param p_manager user event manager. + * + * @return true if writting was successful. +*/ +bool jp2_write_jp2h( + opj_jp2_t *jp2, + opj_stream_private_t *cio, + opj_event_mgr_t * p_manager + ) +{ + opj_jp2_img_header_writer_handler_t l_writers [3]; + opj_jp2_img_header_writer_handler_t * l_current_writer; + + int i, l_nb_pass; + /* size of data for super box*/ + int l_jp2h_size = 8; + bool l_result = true; + + /* to store the data of the super box */ + unsigned char l_jp2h_data [8]; + + // preconditions + assert(cio != 00); + assert(jp2 != 00); + assert(p_manager != 00); + + memset(l_writers,0,sizeof(l_writers)); + + if + (jp2->bpc == 255) + { + l_nb_pass = 3; + l_writers[0].handler = jp2_write_ihdr; + l_writers[1].handler = jp2_write_bpcc; + l_writers[2].handler = jp2_write_colr; + } + else + { + l_nb_pass = 2; + l_writers[0].handler = jp2_write_ihdr; + l_writers[1].handler = jp2_write_colr; + } + + /* write box header */ + /* write JP2H type */ + opj_write_bytes(l_jp2h_data+4,JP2_JP2H,4); + + l_current_writer = l_writers; + for + (i=0;i<l_nb_pass;++i) + { + l_current_writer->m_data = l_current_writer->handler(jp2,&(l_current_writer->m_size)); + if + (l_current_writer->m_data == 00) + { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to hold JP2 Header data\n"); + l_result = false; + break; + } + l_jp2h_size += l_current_writer->m_size; + ++l_current_writer; + } - opj_common_ptr cinfo = jp2->cinfo; + if + (! l_result) + { + l_current_writer = l_writers; + for + (i=0;i<l_nb_pass;++i) + { + if + (l_current_writer->m_data != 00) + { + opj_free(l_current_writer->m_data ); + } + ++l_current_writer; + } + return false; + } - jp2_read_boxhdr(cinfo, cio, &box); - do { - if (JP2_JP2H != box.type) { - if (box.type == JP2_JP2C) { - opj_event_msg(cinfo, EVT_ERROR, "Expected JP2H Marker\n"); - return false; + /* write super box size */ + opj_write_bytes(l_jp2h_data,l_jp2h_size,4); + + /* write super box data on stream */ + if + (opj_stream_write_data(cio,l_jp2h_data,8,p_manager) != 8) + { + opj_event_msg(p_manager, EVT_ERROR, "Stream error while writting JP2 Header box\n"); + l_result = false; + } + + if + (l_result) + { + l_current_writer = l_writers; + for + (i=0;i<l_nb_pass;++i) + { + if + (opj_stream_write_data(cio,l_current_writer->m_data,l_current_writer->m_size,p_manager) != l_current_writer->m_size) + { + opj_event_msg(p_manager, EVT_ERROR, "Stream error while writting JP2 Header box\n"); + l_result = false; + break; } - cio_skip(cio, box.length - 8); - jp2_read_boxhdr(cinfo, cio, &box); + ++l_current_writer; + } + } + l_current_writer = l_writers; + /* cleanup */ + for + (i=0;i<l_nb_pass;++i) + { + if + (l_current_writer->m_data != 00) + { + opj_free(l_current_writer->m_data ); } - } while(JP2_JP2H != box.type); + ++l_current_writer; + } + return l_result; +} - if (!jp2_read_ihdr(jp2, cio)) +/** + * Reads the Jpeg2000 file Header box - JP2 Header box (warning, this is a super box). + * + * @param p_header_data the data contained in the file header box. + * @param jp2 the jpeg2000 file codec. + * @param p_header_size the size of the data contained in the file header box. + * @param p_manager the user event manager. + * + * @return true if the JP2 Header box was successfully reconized. +*/ +bool jp2_read_jp2h( + opj_jp2_t *jp2, + unsigned char * p_header_data, + unsigned int p_header_size, + opj_event_mgr_t * p_manager + ) +{ + unsigned int l_box_size=0, l_current_data_size = 0; + opj_jp2_box_t box; + const opj_jp2_header_handler_t * l_current_handler; + + // preconditions + assert(p_header_data != 00); + assert(jp2 != 00); + assert(p_manager != 00); + + /* make sure the box is well placed */ + if + ((jp2->jp2_state & JP2_STATE_FILE_TYPE) != JP2_STATE_FILE_TYPE ) + { + opj_event_msg(p_manager, EVT_ERROR, "The box must be the first box in the file.\n"); return false; - - if (jp2->bpc == 255) { - if (!jp2_read_bpcc(jp2, cio)) + } + jp2->jp2_img_state = JP2_IMG_STATE_NONE; + + /* iterate while remaining data */ + while + (p_header_size > 0) + { + if + (! jp2_read_boxhdr_char(&box,p_header_data,&l_box_size,p_header_size, p_manager)) + { + opj_event_msg(p_manager, EVT_ERROR, "Stream error while reading JP2 Header box\n"); + return false; + } + if + (box.length > p_header_size) + { + opj_event_msg(p_manager, EVT_ERROR, "Stream error while reading JP2 Header box\n"); return false; + } + l_current_handler = jp2_img_find_handler(box.type); + + l_current_data_size = box.length - l_box_size; + p_header_data += l_box_size; + + if + (l_current_handler != 00) + { + if + (! l_current_handler->handler(jp2,p_header_data,l_current_data_size,p_manager)) + { + return false; + } + } + else + { + jp2->jp2_img_state |= JP2_IMG_STATE_UNKNOWN; + } + p_header_data += l_current_data_size; + p_header_size -= box.length; } - if (!jp2_read_colr(jp2, cio)) - return false; + jp2->jp2_state |= JP2_STATE_HEADER; + return true; +} - skip_len = box.init_pos + box.length - cio_tell(cio); - if (skip_len < 0) { - opj_event_msg(cinfo, EVT_ERROR, "Error with JP2H Box\n"); +/** + * Reads a IHDR box - Image Header box + * + * @param p_image_header_data pointer to actual data (already read from file) + * @param jp2 the jpeg2000 file codec. + * @param p_image_header_size the size of the image header + * @param p_image_header_max_size maximum size of the header, any size bigger than this value should result the function to output false. + * @param p_manager the user event manager. + * + * @return true if the image header is valid, fale else. + */ +bool jp2_read_ihdr( + opj_jp2_t *jp2, + unsigned char * p_image_header_data, + unsigned int p_image_header_size, + opj_event_mgr_t * p_manager + ) +{ + // preconditions + assert(p_image_header_data != 00); + assert(jp2 != 00); + assert(p_manager != 00); + + if + (p_image_header_size != 14) + { + opj_event_msg(p_manager, EVT_ERROR, "Bad image header box (bad size)\n"); return false; } - cio_skip(cio, box.init_pos + box.length - cio_tell(cio)); - + opj_read_bytes(p_image_header_data,&(jp2->h),4); /* HEIGHT */ + p_image_header_data += 4; + opj_read_bytes(p_image_header_data,&(jp2->w),4); /* WIDTH */ + p_image_header_data += 4; + opj_read_bytes(p_image_header_data,&(jp2->numcomps),2); /* NC */ + p_image_header_data += 2; + + /* allocate memory for components */ + jp2->comps = (opj_jp2_comps_t*) opj_malloc(jp2->numcomps * sizeof(opj_jp2_comps_t)); + if + (jp2->comps == 0) + { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to handle image header (ihdr)\n"); + return false; + } + memset(jp2->comps,0,jp2->numcomps * sizeof(opj_jp2_comps_t)); + + opj_read_bytes(p_image_header_data,&(jp2->bpc),1); /* BPC */ + ++ p_image_header_data; + opj_read_bytes(p_image_header_data,&(jp2->C),1); /* C */ + ++ p_image_header_data; + opj_read_bytes(p_image_header_data,&(jp2->UnkC),1); /* UnkC */ + ++ p_image_header_data; + opj_read_bytes(p_image_header_data,&(jp2->IPR),1); /* IPR */ + ++ p_image_header_data; return true; } -static void jp2_write_ftyp(opj_jp2_t *jp2, opj_cio_t *cio) { +/** + * Writes the Image Header box - Image Header box. + * + * @param jp2 jpeg2000 file codec. + * @param p_nb_bytes_written pointer to store the nb of bytes written by the function. + * + * @return the data being copied. +*/ +static unsigned char * jp2_write_ihdr( + opj_jp2_t *jp2, + unsigned int * p_nb_bytes_written + ) +{ + unsigned char * l_ihdr_data,* l_current_ihdr_ptr; + + // preconditions + assert(jp2 != 00); + assert(p_nb_bytes_written != 00); + + /* default image header is 22 bytes wide */ + l_ihdr_data = (unsigned char *) opj_malloc(22); + if + (l_ihdr_data == 00) + { + return 00; + } + memset(l_ihdr_data,0,22); + + l_current_ihdr_ptr = l_ihdr_data; + + opj_write_bytes(l_current_ihdr_ptr,22,4); /* write box size */ + l_current_ihdr_ptr+=4; + opj_write_bytes(l_current_ihdr_ptr,JP2_IHDR, 4); /* IHDR */ + l_current_ihdr_ptr+=4; + opj_write_bytes(l_current_ihdr_ptr,jp2->h, 4); /* HEIGHT */ + l_current_ihdr_ptr+=4; + opj_write_bytes(l_current_ihdr_ptr, jp2->w, 4); /* WIDTH */ + l_current_ihdr_ptr+=4; + opj_write_bytes(l_current_ihdr_ptr, jp2->numcomps, 2); /* NC */ + l_current_ihdr_ptr+=2; + opj_write_bytes(l_current_ihdr_ptr, jp2->bpc, 1); /* BPC */ + ++l_current_ihdr_ptr; + opj_write_bytes(l_current_ihdr_ptr, jp2->C, 1); /* C : Always 7 */ + ++l_current_ihdr_ptr; + opj_write_bytes(l_current_ihdr_ptr, jp2->UnkC, 1); /* UnkC, colorspace unknown */ + ++l_current_ihdr_ptr; + opj_write_bytes(l_current_ihdr_ptr, jp2->IPR, 1); /* IPR, no intellectual property */ + ++l_current_ihdr_ptr; + *p_nb_bytes_written = 22; + return l_ihdr_data; +} + +/** + * Writes the Bit per Component box. + * + * @param jp2 jpeg2000 file codec. + * @param p_nb_bytes_written pointer to store the nb of bytes written by the function. + * + * @return the data being copied. +*/ +unsigned char * jp2_write_bpcc( + opj_jp2_t *jp2, + unsigned int * p_nb_bytes_written + ) +{ unsigned int i; - opj_jp2_box_t box; + /* room for 8 bytes for box and 1 byte for each component */ + int l_bpcc_size = 8 + jp2->numcomps; + unsigned char * l_bpcc_data,* l_current_bpcc_ptr; + + // preconditions + assert(jp2 != 00); + assert(p_nb_bytes_written != 00); + + l_bpcc_data = (unsigned char *) opj_malloc(l_bpcc_size); + if + (l_bpcc_data == 00) + { + return 00; + } + memset(l_bpcc_data,0,l_bpcc_size); - box.init_pos = cio_tell(cio); - cio_skip(cio, 4); - cio_write(cio, JP2_FTYP, 4); /* FTYP */ + l_current_bpcc_ptr = l_bpcc_data; - cio_write(cio, jp2->brand, 4); /* BR */ - cio_write(cio, jp2->minversion, 4); /* MinV */ + opj_write_bytes(l_current_bpcc_ptr,l_bpcc_size,4); /* write box size */ + l_current_bpcc_ptr += 4; + opj_write_bytes(l_current_bpcc_ptr,JP2_BPCC,4); /* BPCC */ + l_current_bpcc_ptr += 4; - for (i = 0; i < jp2->numcl; i++) { - cio_write(cio, jp2->cl[i], 4); /* CL */ + for + (i = 0; i < jp2->numcomps; ++i) + { + opj_write_bytes(l_current_bpcc_ptr, jp2->comps[i].bpcc, 1); /* write each component information */ + ++l_current_bpcc_ptr; } - - box.length = cio_tell(cio) - box.init_pos; - cio_seek(cio, box.init_pos); - cio_write(cio, box.length, 4); /* L */ - cio_seek(cio, box.init_pos + box.length); + *p_nb_bytes_written = l_bpcc_size; + return l_bpcc_data; } -static bool jp2_read_ftyp(opj_jp2_t *jp2, opj_cio_t *cio) { - int i; - opj_jp2_box_t box; - - opj_common_ptr cinfo = jp2->cinfo; +/** + * Reads a Bit per Component box. + * + * @param p_bpc_header_data pointer to actual data (already read from file) + * @param jp2 the jpeg2000 file codec. + * @param p_bpc_header_size pointer that will hold the size of the bpc header + * @param p_bpc_header_max_size maximum size of the header, any size bigger than this value should result the function to output false. + * @param p_manager the user event manager. + * + * @return true if the bpc header is valid, fale else. + */ +bool jp2_read_bpcc( + opj_jp2_t *jp2, + unsigned char * p_bpc_header_data, + unsigned int p_bpc_header_size, + opj_event_mgr_t * p_manager + ) +{ + unsigned int i; - jp2_read_boxhdr(cinfo, cio, &box); + // preconditions + assert(p_bpc_header_data != 00); + assert(jp2 != 00); + assert(p_manager != 00); - if (JP2_FTYP != box.type) { - opj_event_msg(cinfo, EVT_ERROR, "Expected FTYP Marker\n"); + // and length is relevant + if + (p_bpc_header_size != jp2->numcomps) + { + opj_event_msg(p_manager, EVT_ERROR, "Bad BPCC header box (bad size)\n"); return false; } - jp2->brand = cio_read(cio, 4); /* BR */ - jp2->minversion = cio_read(cio, 4); /* MinV */ - jp2->numcl = (box.length - 16) / 4; - jp2->cl = (unsigned int *) opj_malloc(jp2->numcl * sizeof(unsigned int)); + // read info for each component + for + (i = 0; i < jp2->numcomps; ++i) + { + opj_read_bytes(p_bpc_header_data,&jp2->comps[i].bpcc ,1); /* read each BPCC component */ + ++p_bpc_header_data; + } + return true; +} - for (i = 0; i < (int)jp2->numcl; i++) { - jp2->cl[i] = cio_read(cio, 4); /* CLi */ +/** + * Writes the Colour Specification box. + * + * @param jp2 jpeg2000 file codec. + * @param p_nb_bytes_written pointer to store the nb of bytes written by the function. + * + * @return the data being copied. +*/ +unsigned char *jp2_write_colr( + opj_jp2_t *jp2, + unsigned int * p_nb_bytes_written + ) +{ + /* room for 8 bytes for box 3 for common data and variable upon profile*/ + unsigned int l_colr_size = 11; + unsigned char * l_colr_data,* l_current_colr_ptr; + + // preconditions + assert(jp2 != 00); + assert(p_nb_bytes_written != 00); + + switch + (jp2->meth) + { + case 1 : + l_colr_size += 4; + break; + case 2 : + ++l_colr_size; + break; + default : + return 00; } - if (cio_tell(cio) - box.init_pos != box.length) { - opj_event_msg(cinfo, EVT_ERROR, "Error with FTYP Box\n"); - return false; + l_colr_data = (unsigned char *) opj_malloc(l_colr_size); + if + (l_colr_data == 00) + { + return 00; } + memset(l_colr_data,0,l_colr_size); + l_current_colr_ptr = l_colr_data; - return true; + opj_write_bytes(l_current_colr_ptr,l_colr_size,4); /* write box size */ + l_current_colr_ptr += 4; + opj_write_bytes(l_current_colr_ptr,JP2_COLR,4); /* BPCC */ + l_current_colr_ptr += 4; + + opj_write_bytes(l_current_colr_ptr, jp2->meth,1); /* METH */ + ++l_current_colr_ptr; + opj_write_bytes(l_current_colr_ptr, jp2->precedence,1); /* PRECEDENCE */ + ++l_current_colr_ptr; + opj_write_bytes(l_current_colr_ptr, jp2->approx,1); /* APPROX */ + ++l_current_colr_ptr; + + if + (jp2->meth == 1) + { + opj_write_bytes(l_current_colr_ptr, jp2->enumcs,4); /* EnumCS */ + } + else + { + opj_write_bytes(l_current_colr_ptr, 0, 1); /* PROFILE (??) */ + } + *p_nb_bytes_written = l_colr_size; + return l_colr_data; } -static int jp2_write_jp2c(opj_jp2_t *jp2, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info) { - unsigned int j2k_codestream_offset, j2k_codestream_length; - opj_jp2_box_t box; +/** + * Reads the Colour Specification box. + * + * @param p_colr_header_data pointer to actual data (already read from file) + * @param jp2 the jpeg2000 file codec. + * @param p_colr_header_size pointer that will hold the size of the color header + * @param p_colr_header_max_size maximum size of the header, any size bigger than this value should result the function to output false. + * @param p_manager the user event manager. + * + * @return true if the bpc header is valid, fale else. +*/ +bool jp2_read_colr( + opj_jp2_t * jp2, + unsigned char * p_colr_header_data, + unsigned int p_colr_header_size, + opj_event_mgr_t * p_manager + ) +{ + // preconditions + assert(jp2 != 00); + assert(p_colr_header_data != 00); + assert(p_manager != 00); + + if + (p_colr_header_size < 3) + { + opj_event_msg(p_manager, EVT_ERROR, "Bad BPCC header box (bad size)\n"); + return false; + } + + opj_read_bytes(p_colr_header_data,&jp2->meth ,1); /* METH */ + ++p_colr_header_data; - opj_j2k_t *j2k = jp2->j2k; + opj_read_bytes(p_colr_header_data,&jp2->precedence ,1); /* PRECEDENCE */ + ++p_colr_header_data; - box.init_pos = cio_tell(cio); - cio_skip(cio, 4); - cio_write(cio, JP2_JP2C, 4); /* JP2C */ + opj_read_bytes(p_colr_header_data,&jp2->approx ,1); /* APPROX */ + ++p_colr_header_data; + - /* J2K encoding */ - j2k_codestream_offset = cio_tell(cio); - if(!j2k_encode(j2k, cio, image, cstr_info)) { - opj_event_msg(j2k->cinfo, EVT_ERROR, "Failed to encode image\n"); - return 0; + if + (jp2->meth == 1) + { + if + (p_colr_header_size != 7) + { + opj_event_msg(p_manager, EVT_ERROR, "Bad BPCC header box (bad size)\n"); + return false; + } + opj_read_bytes(p_colr_header_data,&jp2->enumcs ,4); /* EnumCS */ } - j2k_codestream_length = cio_tell(cio) - j2k_codestream_offset; + /*else + { + // do not care with profiles. + }*/ + return true; +} - jp2->j2k_codestream_offset = j2k_codestream_offset; - jp2->j2k_codestream_length = j2k_codestream_length; +/** + * Writes the Jpeg2000 codestream Header box - JP2C Header box. + * + * @param cio the stream to write data to. + * @param jp2 the jpeg2000 file codec. + * @param p_manager user event manager. + * + * @return true if writting was successful. +*/ +bool jp2_write_jp2c( + opj_jp2_t *jp2, + opj_stream_private_t *cio, + opj_event_mgr_t * p_manager + ) +{ + unsigned int j2k_codestream_exit; + unsigned char l_data_header [8]; + + // preconditions + assert(jp2 != 00); + assert(cio != 00); + assert(p_manager != 00); + assert(opj_stream_has_seek(cio)); + + j2k_codestream_exit = opj_stream_tell(cio); + opj_write_bytes(l_data_header,j2k_codestream_exit - jp2->j2k_codestream_offset,4); /* size of codestream */ + opj_write_bytes(l_data_header + 4,JP2_JP2C,4); /* JP2C */ + + if + (! opj_stream_seek(cio,jp2->j2k_codestream_offset,p_manager)) + { + opj_event_msg(p_manager, EVT_ERROR, "Failed to seek in the stream.\n"); + return false; + } + + if + (opj_stream_write_data(cio,l_data_header,8,p_manager) != 8) + { + opj_event_msg(p_manager, EVT_ERROR, "Failed to seek in the stream.\n"); + return false; + } - box.length = 8 + jp2->j2k_codestream_length; - cio_seek(cio, box.init_pos); - cio_write(cio, box.length, 4); /* L */ - cio_seek(cio, box.init_pos + box.length); + if + (! opj_stream_seek(cio,j2k_codestream_exit,p_manager)) + { + opj_event_msg(p_manager, EVT_ERROR, "Failed to seek in the stream.\n"); + return false; + } + return true; +} - return box.length; +/** + * Destroys a jpeg2000 file decompressor. + * + * @param jp2 a jpeg2000 file decompressor. + */ +void jp2_destroy(opj_jp2_t *jp2) +{ + if + (jp2) + { + /* destroy the J2K codec */ + j2k_destroy(jp2->j2k); + jp2->j2k = 00; + if + (jp2->comps) + { + opj_free(jp2->comps); + jp2->comps = 00; + } + if + (jp2->cl) + { + opj_free(jp2->cl); + jp2->cl = 00; + } + if + (jp2->m_validation_list) + { + opj_procedure_list_destroy(jp2->m_validation_list); + jp2->m_validation_list = 00; + } + if + (jp2->m_procedure_list) + { + opj_procedure_list_destroy(jp2->m_procedure_list); + jp2->m_procedure_list = 00; + } + opj_free(jp2); + } } -static bool jp2_read_jp2c(opj_jp2_t *jp2, opj_cio_t *cio, unsigned int *j2k_codestream_length, unsigned int *j2k_codestream_offset) { - opj_jp2_box_t box; - opj_common_ptr cinfo = jp2->cinfo; - jp2_read_boxhdr(cinfo, cio, &box); - do { - if(JP2_JP2C != box.type) { - cio_skip(cio, box.length - 8); - jp2_read_boxhdr(cinfo, cio, &box); + + +/* ----------------------------------------------------------------------- */ +/* JP2 encoder interface */ +/* ----------------------------------------------------------------------- */ + +opj_jp2_t* jp2_create(bool p_is_decoder) +{ + opj_jp2_t *jp2 = (opj_jp2_t*)opj_malloc(sizeof(opj_jp2_t)); + if + (jp2) + { + memset(jp2,0,sizeof(opj_jp2_t)); + /* create the J2K codec */ + if + (! p_is_decoder) + { + jp2->j2k = j2k_create_compress(); + } + else + { + jp2->j2k = j2k_create_decompress(); + } + if + (jp2->j2k == 00) + { + jp2_destroy(jp2); + return 00; + } + // validation list creation + jp2->m_validation_list = opj_procedure_list_create(); + if + (! jp2->m_validation_list) + { + jp2_destroy(jp2); + return 00; } - } while(JP2_JP2C != box.type); - *j2k_codestream_offset = cio_tell(cio); - *j2k_codestream_length = box.length - 8; + // execution list creation + jp2->m_procedure_list = opj_procedure_list_create(); + if + (! jp2->m_procedure_list) + { + jp2_destroy(jp2); + return 00; + } + } + return jp2; +} - return true; +/** + * Excutes the given procedures on the given codec. + * + * @param p_procedure_list the list of procedures to execute + * @param jp2 the jpeg2000 file codec to execute the procedures on. + * @param cio the stream to execute the procedures on. + * @param p_manager the user manager. + * + * @return true if all the procedures were successfully executed. + */ +bool jp2_exec ( + opj_jp2_t * jp2, + opj_procedure_list_t * p_procedure_list, + opj_stream_private_t *cio, + opj_event_mgr_t * p_manager + ) +{ + bool (** l_procedure) (opj_jp2_t * jp2,opj_stream_private_t *,opj_event_mgr_t *) = 00; + bool l_result = true; + unsigned int l_nb_proc, i; + + // preconditions + assert(p_procedure_list != 00); + assert(jp2 != 00); + assert(cio != 00); + assert(p_manager != 00); + + l_nb_proc = opj_procedure_list_get_nb_procedures(p_procedure_list); + l_procedure = (bool (**) (opj_jp2_t * jp2,opj_stream_private_t *,opj_event_mgr_t *)) opj_procedure_list_get_first_procedure(p_procedure_list); + for + (i=0;i<l_nb_proc;++i) + { + l_result = l_result && (*l_procedure) (jp2,cio,p_manager); + ++l_procedure; + } + // and clear the procedure list at the end. + opj_procedure_list_clear(p_procedure_list); + return l_result; } -static void jp2_write_jp(opj_cio_t *cio) { - opj_jp2_box_t box; - box.init_pos = cio_tell(cio); - cio_skip(cio, 4); - cio_write(cio, JP2_JP, 4); /* JP2 signature */ - cio_write(cio, 0x0d0a870a, 4); +/** + * Starts a compression scheme, i.e. validates the codec parameters, writes the header. + * + * @param jp2 the jpeg2000 file codec. + * @param cio the stream object. + * + * @return true if the codec is valid. + */ +bool jp2_start_compress(opj_jp2_t *jp2, struct opj_stream_private *cio,opj_image_t * p_image, struct opj_event_mgr * p_manager) +{ + // preconditions + assert(jp2 != 00); + assert(cio != 00); + assert(p_manager != 00); + + /* customization of the validation */ + jp2_setup_encoding_validation (jp2); + + /* validation of the parameters codec */ + if + (! jp2_exec(jp2,jp2->m_validation_list,cio,p_manager)) + { + return false; + } - box.length = cio_tell(cio) - box.init_pos; - cio_seek(cio, box.init_pos); - cio_write(cio, box.length, 4); /* L */ - cio_seek(cio, box.init_pos + box.length); + /* customization of the encoding */ + jp2_setup_header_writting(jp2); + + /* write header */ + if + (! jp2_exec (jp2,jp2->m_procedure_list,cio,p_manager)) + { + return false; + } + return j2k_start_compress(jp2->j2k,cio,p_image,p_manager); } -static bool jp2_read_jp(opj_jp2_t *jp2, opj_cio_t *cio) { - opj_jp2_box_t box; +/** + * Reads a jpeg2000 file header structure. + * + * @param cio the stream to read data from. + * @param jp2 the jpeg2000 file header structure. + * @param p_manager the user event manager. + * + * @return true if the box is valid. + */ +bool jp2_read_header( + opj_jp2_t *jp2, + 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, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager + ) +{ + // preconditions + assert(jp2 != 00); + assert(cio != 00); + assert(p_manager != 00); + + /* customization of the validation */ + jp2_setup_decoding_validation (jp2); + + /* customization of the encoding */ + jp2_setup_header_reading(jp2); - opj_common_ptr cinfo = jp2->cinfo; + /* validation of the parameters codec */ + if + (! jp2_exec(jp2,jp2->m_validation_list,cio,p_manager)) + { + return false; + } - jp2_read_boxhdr(cinfo, cio, &box); - if (JP2_JP != box.type) { - opj_event_msg(cinfo, EVT_ERROR, "Expected JP Marker\n"); + /* read header */ + if + (! jp2_exec (jp2,jp2->m_procedure_list,cio,p_manager)) + { return false; } - if (0x0d0a870a != cio_read(cio, 4)) { - opj_event_msg(cinfo, EVT_ERROR, "Error with JP Marker\n"); + return j2k_read_header( + jp2->j2k, + p_image, + p_tile_x0, + p_tile_y0, + p_tile_width, + p_tile_height, + p_nb_tiles_x, + p_nb_tiles_y, + cio, + p_manager); +} + +/** + * Ends the decompression procedures and possibiliy add data to be read after the + * codestream. + */ +bool jp2_end_decompress(opj_jp2_t *jp2, opj_stream_private_t *cio, opj_event_mgr_t * p_manager) +{ + // preconditions + assert(jp2 != 00); + assert(cio != 00); + assert(p_manager != 00); + + /* customization of the end encoding */ + jp2_setup_end_header_reading(jp2); + + /* write header */ + if + (! jp2_exec (jp2,jp2->m_procedure_list,cio,p_manager)) + { return false; } - if (cio_tell(cio) - box.init_pos != box.length) { - opj_event_msg(cinfo, EVT_ERROR, "Error with JP Box size\n"); + return j2k_end_decompress(jp2->j2k, cio, p_manager); +} + + +/** + * Ends the compression procedures and possibiliy add data to be read after the + * codestream. + */ +bool jp2_end_compress(opj_jp2_t *jp2, opj_stream_private_t *cio, opj_event_mgr_t * p_manager) +{ + // preconditions + assert(jp2 != 00); + assert(cio != 00); + assert(p_manager != 00); + + /* customization of the end encoding */ + jp2_setup_end_header_writting(jp2); + + if + (! j2k_end_compress(jp2->j2k,cio,p_manager)) + { return false; } + /* write header */ + return jp2_exec (jp2,jp2->m_procedure_list,cio,p_manager); +} - return true; +/** +Encode an image into a JPEG-2000 file stream +@param jp2 JP2 compressor handle +@param cio Output buffer stream +@param image Image to encode +@param cstr_info Codestream information structure if required, NULL otherwise +@return Returns true if successful, returns false otherwise +*/ +bool jp2_encode(opj_jp2_t *jp2, struct opj_stream_private *cio, struct opj_event_mgr * p_manager) +{ + return j2k_encode(jp2->j2k,cio,p_manager); +} +/** + * Writes a tile. + * @param p_j2k the jpeg2000 codec. + * @param p_stream the stream to write data to. + * @param p_manager the user event manager. + */ +bool jp2_write_tile ( + opj_jp2_t *p_jp2, + OPJ_UINT32 p_tile_index, + OPJ_BYTE * p_data, + OPJ_UINT32 p_data_size, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + return j2k_write_tile (p_jp2->j2k,p_tile_index,p_data,p_data_size,p_stream,p_manager); } +/** + * Decode tile data. + * @param p_j2k the jpeg2000 codec. + * @param p_stream the stream to write data to. + * @param p_manager the user event manager. + */ +bool jp2_decode_tile ( + opj_jp2_t * p_jp2, + 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 + ) +{ + return j2k_decode_tile (p_jp2->j2k,p_tile_index,p_data,p_data_size,p_stream,p_manager); +} +/** + * 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. + */ +bool jp2_read_tile_header ( + opj_jp2_t * p_jp2, + 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, + bool * p_go_on, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ) +{ + return j2k_read_tile_header (p_jp2->j2k, + p_tile_index, + p_data_size, + p_tile_x0, + p_tile_y0, + p_tile_x1, + p_tile_y1, + p_nb_comps, + p_go_on, + p_stream, + p_manager); +} -static bool jp2_read_struct(opj_jp2_t *jp2, opj_cio_t *cio) { - if (!jp2_read_jp(jp2, cio)) - return false; - if (!jp2_read_ftyp(jp2, cio)) - return false; - if (!jp2_read_jp2h(jp2, cio)) - return false; - if (!jp2_read_jp2c(jp2, cio, &jp2->j2k_codestream_length, &jp2->j2k_codestream_offset)) - return false; - - return true; +/** + * Sets up the procedures to do on writting header after the codestream. + * Developpers wanting to extend the library can add their own writting procedures. + */ +void jp2_setup_end_header_writting (opj_jp2_t *jp2) +{ + // preconditions + assert(jp2 != 00); + + opj_procedure_list_add_procedure(jp2->m_procedure_list,jp2_write_jp2c ); + /* DEVELOPER CORNER, add your custom procedures */ } -/* ----------------------------------------------------------------------- */ -/* JP2 decoder interface */ -/* ----------------------------------------------------------------------- */ +/** + * Sets up the procedures to do on reading header. + * Developpers wanting to extend the library can add their own writting procedures. + */ +void jp2_setup_header_reading (opj_jp2_t *jp2) +{ + // preconditions + assert(jp2 != 00); -opj_jp2_t* jp2_create_decompress(opj_common_ptr cinfo) { - opj_jp2_t *jp2 = (opj_jp2_t*) opj_calloc(1, sizeof(opj_jp2_t)); - if(jp2) { - jp2->cinfo = cinfo; - /* create the J2K codec */ - jp2->j2k = j2k_create_decompress(cinfo); - if(jp2->j2k == NULL) { - jp2_destroy_decompress(jp2); - return NULL; - } - } - return jp2; + opj_procedure_list_add_procedure(jp2->m_procedure_list,jp2_read_header_procedure ); + /* DEVELOPER CORNER, add your custom procedures */ } -void jp2_destroy_decompress(opj_jp2_t *jp2) { - if(jp2) { - /* destroy the J2K codec */ - j2k_destroy_decompress(jp2->j2k); +/** + * Sets up the procedures to do on reading header after the codestream. + * Developpers wanting to extend the library can add their own writting procedures. + */ +void jp2_setup_end_header_reading (opj_jp2_t *jp2) +{ + // preconditions + assert(jp2 != 00); + opj_procedure_list_add_procedure(jp2->m_procedure_list,jp2_read_header_procedure ); + /* DEVELOPER CORNER, add your custom procedures */ +} - if(jp2->comps) { - opj_free(jp2->comps); - } - if(jp2->cl) { - opj_free(jp2->cl); - } - opj_free(jp2); + +/** + * The default validation procedure without any extension. + * + * @param jp2 the jpeg2000 codec to validate. + * @param cio the input stream to validate. + * @param p_manager the user event manager. + * + * @return true if the parameters are correct. + */ +bool jp2_default_validation ( + opj_jp2_t * jp2, + opj_stream_private_t *cio, + opj_event_mgr_t * p_manager + ) +{ + bool l_is_valid = true; + unsigned int i; + + // preconditions + assert(jp2 != 00); + assert(cio != 00); + assert(p_manager != 00); + /* JPEG2000 codec validation */ + /*TODO*/ + + /* STATE checking */ + /* make sure the state is at 0 */ + l_is_valid &= (jp2->jp2_state == JP2_STATE_NONE); + /* make sure not reading a jp2h ???? WEIRD */ + l_is_valid &= (jp2->jp2_img_state == JP2_IMG_STATE_NONE); + + /* POINTER validation */ + /* make sure a j2k codec is present */ + l_is_valid &= (jp2->j2k != 00); + /* make sure a procedure list is present */ + l_is_valid &= (jp2->m_procedure_list != 00); + /* make sure a validation list is present */ + l_is_valid &= (jp2->m_validation_list != 00); + + /* PARAMETER VALIDATION */ + /* number of components */ + l_is_valid &= (jp2->numcl > 0); + /* width */ + l_is_valid &= (jp2->h > 0); + /* height */ + l_is_valid &= (jp2->w > 0); + /* precision */ + for + (i = 0; i < jp2->numcomps; ++i) + { + l_is_valid &= (jp2->comps[i].bpcc > 0); } + /* METH */ + l_is_valid &= ((jp2->meth > 0) && (jp2->meth < 3)); + + + + /* stream validation */ + /* back and forth is needed */ + l_is_valid &= opj_stream_has_seek(cio); + + return l_is_valid; + } -void jp2_setup_decoder(opj_jp2_t *jp2, opj_dparameters_t *parameters) { - /* setup the J2K codec */ - j2k_setup_decoder(jp2->j2k, parameters); - /* further JP2 initializations go here */ +/** + * 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 jp2_setup_encoding_validation (opj_jp2_t *jp2) +{ + // preconditions + assert(jp2 != 00); + opj_procedure_list_add_procedure(jp2->m_validation_list, jp2_default_validation); + /* DEVELOPER CORNER, add your custom validation procedure */ } -opj_image_t* jp2_decode(opj_jp2_t *jp2, opj_cio_t *cio, opj_codestream_info_t *cstr_info) { - opj_common_ptr cinfo; - opj_image_t *image = NULL; +/** + * 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 jp2_setup_decoding_validation (opj_jp2_t *jp2) +{ + // preconditions + assert(jp2 != 00); + /* DEVELOPER CORNER, add your custom validation procedure */ +} - if(!jp2 || !cio) { - return NULL; - } +/** + * Sets up the procedures to do on writting header. Developpers wanting to extend the library can add their own writting procedures. + */ +void jp2_setup_header_writting (opj_jp2_t *jp2) +{ + // preconditions + assert(jp2 != 00); + opj_procedure_list_add_procedure(jp2->m_procedure_list,jp2_write_jp ); + opj_procedure_list_add_procedure(jp2->m_procedure_list,jp2_write_ftyp ); + opj_procedure_list_add_procedure(jp2->m_procedure_list,jp2_write_jp2h ); + opj_procedure_list_add_procedure(jp2->m_procedure_list,jp2_skip_jp2c ); + + /* DEVELOPER CORNER, insert your custom procedures */ + +} - cinfo = jp2->cinfo; - /* JP2 decoding */ - if(!jp2_read_struct(jp2, cio)) { - opj_event_msg(cinfo, EVT_ERROR, "Failed to decode jp2 structure\n"); - return NULL; +/** + * Skips the Jpeg2000 Codestream Header box - JP2C Header box. + * + * @param cio the stream to write data to. + * @param jp2 the jpeg2000 file codec. + * @param p_manager user event manager. + * + * @return true if writting was successful. +*/ +bool jp2_skip_jp2c( + opj_jp2_t *jp2, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager + ) +{ + // preconditions + assert(jp2 != 00); + assert(cio != 00); + assert(p_manager != 00); + + jp2->j2k_codestream_offset = opj_stream_tell(cio); + if + (opj_stream_skip(cio,8,p_manager) != 8) + { + return false; } + return true; +} +struct opj_image * jp2_decode(opj_jp2_t *jp2, struct opj_stream_private *cio, struct opj_event_mgr * p_manager) +{ /* J2K decoding */ - image = j2k_decode(jp2->j2k, cio, cstr_info); - if(!image) { - opj_event_msg(cinfo, EVT_ERROR, "Failed to decode J2K image\n"); - return NULL; + struct opj_image * image = j2k_decode(jp2->j2k, cio, p_manager); + if + (!image) + { + opj_event_msg(p_manager, EVT_ERROR, "Failed to decode J2K image\n"); + return false; } /* Set Image Color Space */ @@ -573,45 +2086,12 @@ opj_image_t* jp2_decode(opj_jp2_t *jp2, opj_cio_t *cio, opj_codestream_info_t *c image->color_space = CLRSPC_SYCC; else image->color_space = CLRSPC_UNKNOWN; - return image; } -/* ----------------------------------------------------------------------- */ -/* JP2 encoder interface */ -/* ----------------------------------------------------------------------- */ - -opj_jp2_t* jp2_create_compress(opj_common_ptr cinfo) { - opj_jp2_t *jp2 = (opj_jp2_t*)opj_malloc(sizeof(opj_jp2_t)); - if(jp2) { - jp2->cinfo = cinfo; - /* create the J2K codec */ - jp2->j2k = j2k_create_compress(cinfo); - if(jp2->j2k == NULL) { - jp2_destroy_compress(jp2); - return NULL; - } - } - return jp2; -} - -void jp2_destroy_compress(opj_jp2_t *jp2) { - if(jp2) { - /* destroy the J2K codec */ - j2k_destroy_compress(jp2->j2k); - - if(jp2->comps) { - opj_free(jp2->comps); - } - if(jp2->cl) { - opj_free(jp2->cl); - } - opj_free(jp2); - } -} - -void jp2_setup_encoder(opj_jp2_t *jp2, opj_cparameters_t *parameters, opj_image_t *image) { - int i; +void jp2_setup_encoder(opj_jp2_t *jp2, opj_cparameters_t *parameters, opj_image_t *image,opj_event_mgr_t * p_manager) +{ + unsigned int i; int depth_0, sign; if(!jp2 || !parameters || !image) @@ -622,11 +2102,11 @@ void jp2_setup_encoder(opj_jp2_t *jp2, opj_cparameters_t *parameters, opj_image_ /* Check if number of components respects standard */ if (image->numcomps < 1 || image->numcomps > 16384) { - opj_event_msg(jp2->cinfo, EVT_ERROR, "Invalid number of components specified while setting up JP2 encoder\n"); + opj_event_msg(p_manager, EVT_ERROR, "Invalid number of components specified while setting up JP2 encoder\n"); return; } - j2k_setup_encoder(jp2->j2k, parameters, image); + j2k_setup_encoder(jp2->j2k, parameters, image,p_manager); /* setup the JP2 codec */ /* ------------------- */ @@ -687,25 +2167,63 @@ void jp2_setup_encoder(opj_jp2_t *jp2, opj_cparameters_t *parameters, opj_image_ } -bool jp2_encode(opj_jp2_t *jp2, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info) { +void jp2_setup_decoder(opj_jp2_t *jp2, opj_dparameters_t *parameters) +{ + if(!jp2 || !parameters) + return; + + /* setup the J2K codec */ + /* ------------------- */ + j2k_setup_decoder(jp2->j2k, parameters); +} +/** + * 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_jp2 the jpeg2000 codec. + * @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. + */ +bool jp2_set_decode_area( + opj_jp2_t *p_jp2, + 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 + ) +{ + return j2k_set_decode_area(p_jp2->j2k,p_start_x,p_start_y,p_end_x,p_end_y,p_manager); +} - /* JP2 encoding */ +#if 0 - /* JPEG 2000 Signature box */ - jp2_write_jp(cio); - /* File Type box */ - jp2_write_ftyp(jp2, cio); - /* JP2 Header box */ - jp2_write_jp2h(jp2, cio); - /* J2K encoding */ - if(!jp2_write_jp2c(jp2, cio, image, cstr_info)) { - opj_event_msg(jp2->cinfo, EVT_ERROR, "Failed to encode image\n"); - return false; - } - return true; -} +static void jp2_write_url(opj_cio_t *cio, char *Idx_file) { + unsigned int i; + opj_jp2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio, 4); + cio_write(cio, JP2_URL, 4); /* DBTL */ + cio_write(cio, 0, 1); /* VERS */ + cio_write(cio, 0, 3); /* FLAG */ + + if(Idx_file) { + for (i = 0; i < strlen(Idx_file); i++) { + cio_write(cio, Idx_file[i], 1); + } + } + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} +#endif diff --git a/libopenjpeg/jp2.h b/libopenjpeg/jp2.h index 7e363be2..e98cde39 100644 --- a/libopenjpeg/jp2.h +++ b/libopenjpeg/jp2.h @@ -3,6 +3,7 @@ * Copyright (c) 2002-2007, Professor Benoit Macq * Copyright (c) 2002-2003, Yannick Verschueren * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -33,6 +34,20 @@ @brief The JPEG-2000 file format Reader/Writer (JP2) */ +#include "openjpeg.h" + + + + +/********************************************************************************** + ********************************* FORWARD DECLARATIONS *************************** + **********************************************************************************/ +struct opj_j2k; +struct opj_procedure_list; +struct opj_event_mgr; +struct opj_stream_private; +struct opj_dparameters; +struct opj_cparameters; /** @defgroup JP2 JP2 - JPEG-2000 file format reader/writer */ /*@{*/ @@ -52,25 +67,54 @@ /* ----------------------------------------------------------------------- */ + +typedef enum +{ + JP2_STATE_NONE = 0x0, + JP2_STATE_SIGNATURE = 0x1, + JP2_STATE_FILE_TYPE = 0x2, + JP2_STATE_HEADER = 0x4, + JP2_STATE_CODESTREAM = 0x8, + JP2_STATE_END_CODESTREAM = 0x10, + JP2_STATE_UNKNOWN = 0x80000000 +} +JP2_STATE; + +typedef enum +{ + JP2_IMG_STATE_NONE = 0x0, + JP2_IMG_STATE_UNKNOWN = 0x80000000 +} +JP2_IMG_STATE; + /** JP2 component */ -typedef struct opj_jp2_comps { - int depth; +typedef struct opj_jp2_comps +{ + unsigned int depth; int sgnd; - int bpcc; -} opj_jp2_comps_t; + unsigned int bpcc; +} +opj_jp2_comps_t; /** JPEG-2000 file format reader/writer */ -typedef struct opj_jp2 { - /** codec context */ - opj_common_ptr cinfo; +typedef struct opj_jp2 +{ /** handle to the J2K codec */ - opj_j2k_t *j2k; + struct opj_j2k *j2k; + /** list of validation procedures */ + struct opj_procedure_list * m_validation_list; + /** list of execution procedures */ + struct opj_procedure_list * m_procedure_list; + + /* width of image */ unsigned int w; + /* height of image */ unsigned int h; + /* number of components in the image */ unsigned int numcomps; unsigned int bpc; unsigned int C; @@ -86,71 +130,80 @@ typedef struct opj_jp2 { unsigned int *cl; opj_jp2_comps_t *comps; unsigned int j2k_codestream_offset; - unsigned int j2k_codestream_length; -} opj_jp2_t; + unsigned int jp2_state; + unsigned int jp2_img_state; + +} +opj_jp2_t; /** JP2 Box */ -typedef struct opj_jp2_box { - int length; - int type; - int init_pos; -} opj_jp2_box_t; +typedef struct opj_jp2_box +{ + unsigned int length; + unsigned int type; +} +opj_jp2_box_t; + +typedef struct opj_jp2_header_handler +{ + /* marker value */ + int id; + /* action linked to the marker */ + bool (*handler) (opj_jp2_t *jp2,unsigned char * p_header_data, unsigned int p_header_size,struct opj_event_mgr * p_manager); +} +opj_jp2_header_handler_t; + + +typedef struct opj_jp2_img_header_writer_handler +{ + /* action to perform */ + unsigned char* (*handler) (opj_jp2_t *jp2, unsigned int * p_data_size); + /* result of the action : data */ + unsigned char * m_data; + /* size of data */ + unsigned int m_size; +} +opj_jp2_img_header_writer_handler_t; + + + + /** @name Exported functions */ /*@{*/ /* ----------------------------------------------------------------------- */ + /** -Write the JP2H box - JP2 Header box (used in MJ2) -@param jp2 JP2 handle -@param cio Output buffer stream -*/ -void jp2_write_jp2h(opj_jp2_t *jp2, opj_cio_t *cio); -/** -Read the JP2H box - JP2 Header box (used in MJ2) -@param jp2 JP2 handle -@param cio Input buffer stream -@return Returns true if successful, returns false otherwise -*/ -bool jp2_read_jp2h(opj_jp2_t *jp2, opj_cio_t *cio); -/** -Creates a JP2 decompression structure -@param cinfo Codec context info -@return Returns a handle to a JP2 decompressor if successful, returns NULL otherwise -*/ -opj_jp2_t* jp2_create_decompress(opj_common_ptr cinfo); + * Creates a jpeg2000 file decompressor. + * + * @return an empty jpeg2000 file codec. + */ +opj_jp2_t* jp2_create (bool p_is_decoder); + /** Destroy a JP2 decompressor handle @param jp2 JP2 decompressor handle to destroy */ -void jp2_destroy_decompress(opj_jp2_t *jp2); +void jp2_destroy(opj_jp2_t *jp2); + /** Setup the decoder decoding parameters using user parameters. Decoding parameters are returned in jp2->j2k->cp. @param jp2 JP2 decompressor handle @param parameters decompression parameters */ -void jp2_setup_decoder(opj_jp2_t *jp2, opj_dparameters_t *parameters); -/** -Decode an image from a JPEG-2000 file stream -@param jp2 JP2 decompressor handle -@param cio Input buffer stream -@param cstr_info Codestream information structure if required, NULL otherwise -@return Returns a decoded image if successful, returns NULL otherwise -*/ -opj_image_t* jp2_decode(opj_jp2_t *jp2, opj_cio_t *cio, opj_codestream_info_t *cstr_info); -/** -Creates a JP2 compression structure -@param cinfo Codec context info -@return Returns a handle to a JP2 compressor if successful, returns NULL otherwise -*/ -opj_jp2_t* jp2_create_compress(opj_common_ptr cinfo); +void jp2_setup_decoder(opj_jp2_t *jp2, struct opj_dparameters *parameters); + /** -Destroy a JP2 compressor handle -@param jp2 JP2 compressor handle to destroy + * Decode an image from a JPEG-2000 file stream + * @param jp2 JP2 decompressor handle + * @param cio Input buffer stream + * @param cstr_info Codestream information structure if required, NULL otherwise + * @return Returns a decoded image if successful, returns NULL otherwise */ -void jp2_destroy_compress(opj_jp2_t *jp2); +struct opj_image* jp2_decode(opj_jp2_t *jp2, struct opj_stream_private *cio, struct opj_event_mgr * p_manager); /** Setup the encoder parameters using the current image and using user parameters. Coding parameters are returned in jp2->j2k->cp. @@ -158,7 +211,24 @@ Coding parameters are returned in jp2->j2k->cp. @param parameters compression parameters @param image input filled image */ -void jp2_setup_encoder(opj_jp2_t *jp2, opj_cparameters_t *parameters, opj_image_t *image); +void jp2_setup_encoder(opj_jp2_t *jp2, struct opj_cparameters *parameters, struct opj_image *image,struct opj_event_mgr * p_manager); + +/** + * Starts a compression scheme, i.e. validates the codec parameters, writes the header. + * + * @param jp2 the jpeg2000 file codec. + * @param cio the stream object. + * + * @return true if the codec is valid. + */ +bool jp2_start_compress(opj_jp2_t *jp2, struct opj_stream_private *cio,struct opj_image * p_image,struct opj_event_mgr * p_manager); + +/** + * Ends the compression procedures and possibiliy add data to be read after the + * codestream. + */ +bool jp2_end_compress(opj_jp2_t *jp2, struct opj_stream_private *cio, struct opj_event_mgr * p_manager); + /** Encode an image into a JPEG-2000 file stream @param jp2 JP2 compressor handle @@ -167,7 +237,102 @@ Encode an image into a JPEG-2000 file stream @param cstr_info Codestream information structure if required, NULL otherwise @return Returns true if successful, returns false otherwise */ -bool jp2_encode(opj_jp2_t *jp2, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info); +bool jp2_encode(opj_jp2_t *jp2, struct opj_stream_private *cio, struct opj_event_mgr * p_manager); + +/** + * Reads a jpeg2000 file header structure. + * + * @param cio the stream to read data from. + * @param jp2 the jpeg2000 file header structure. + * @param p_manager the user event manager. + * + * @return true if the box is valid. + */ +bool jp2_read_header( + opj_jp2_t *jp2, + 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, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager + ); +/** + * Ends the decompression procedures and possibiliy add data to be read after the + * codestream. + */ +bool jp2_end_decompress(opj_jp2_t *jp2, struct opj_stream_private *cio, struct opj_event_mgr * p_manager); + +/** + * Writes a tile. + * @param p_j2k the jpeg2000 codec. + * @param p_stream the stream to write data to. + * @param p_manager the user event manager. + */ +bool jp2_write_tile ( + opj_jp2_t *p_jp2, + OPJ_UINT32 p_tile_index, + OPJ_BYTE * p_data, + OPJ_UINT32 p_data_size, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); +/** + * Decode tile data. + * @param p_j2k the jpeg2000 codec. + * @param p_stream the stream to write data to. + * @param p_manager the user event manager. + */ +bool jp2_decode_tile ( + opj_jp2_t * p_jp2, + OPJ_UINT32 p_tile_index, + OPJ_BYTE * p_data, + OPJ_UINT32 p_data_size, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); +/** + * 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. + */ +bool jp2_read_tile_header ( + opj_jp2_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, + bool * p_go_on, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); +/** + * 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_jp2 the jpeg2000 codec. + * @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. + */ +bool jp2_set_decode_area( + opj_jp2_t *p_jp2, + 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 + ); + /* ----------------------------------------------------------------------- */ /*@}*/ diff --git a/libopenjpeg/jpt.c b/libopenjpeg/jpt.c index a2566ea8..dcbafbd9 100644 --- a/libopenjpeg/jpt.c +++ b/libopenjpeg/jpt.c @@ -3,6 +3,7 @@ * Copyright (c) 2002-2007, Professor Benoit Macq * Copyright (c) 2002-2003, Yannick Verschueren * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,33 +28,61 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "opj_includes.h" - +#include "jpt.h" +#include "openjpeg.h" +#include "cio.h" +#include "event.h" /* * Read the information contains in VBAS [JPP/JPT stream message header] * Store information (7 bits) in value - * + * @param p_cio the stream to read from. + * @param p_value the data to update + * @return the nb of bytes read or -1 if an io error occurred. */ -unsigned int jpt_read_VBAS_info(opj_cio_t *cio, unsigned int value) { - unsigned char elmt; - - elmt = cio_read(cio, 1); - while ((elmt >> 7) == 1) { - value = (value << 7); - value |= (elmt & 0x7f); - elmt = cio_read(cio, 1); +bool jpt_read_VBAS_info(opj_stream_private_t * p_cio, OPJ_UINT32 * p_nb_bytes_read, OPJ_UINT32 * p_value, opj_event_mgr_t * p_manager) +{ + OPJ_BYTE l_elmt; + OPJ_UINT32 l_nb_bytes_read = 0; + + // read data till the MSB of the current byte is 1. + // concatenate 7 bits of data, last bit is finish flag + + // read data from the stream + + if + (opj_stream_read_data(p_cio,&l_elmt,1,p_manager) != 1) + { + opj_event_msg(p_manager, EVT_ERROR, "Error trying to read a byte of data.\n"); + return false; } - value = (value << 7); - value |= (elmt & 0x7f); - - return value; + ++l_nb_bytes_read; + + // is the MSB equal to 1 ? + while + (l_elmt & 0x80) + { + // concatenate 7 bits of data, last bit is finish flag + *p_value = (*p_value << 7) | (l_elmt & 0x7f); + if + (opj_stream_read_data(p_cio,&l_elmt,1,p_manager) != 1) + { + opj_event_msg(p_manager, EVT_ERROR, "Error trying to read a byte of data.\n"); + return false; + } + ++l_nb_bytes_read; + } + // concatenate 7 bits of data, last bit is finish flag + *p_value = (*p_value << 7) | (l_elmt & 0x7f); + * p_nb_bytes_read = l_nb_bytes_read; + return true; } /* * Initialize the value of the message header structure * */ -void jpt_init_msg_header(opj_jpt_msg_header_t * header) { +void jpt_init_msg_header(opj_jpt_msg_header_t * header) +{ header->Id = 0; /* In-class Identifier */ header->last_byte = 0; /* Last byte information */ header->Class_Id = 0; /* Class Identifier */ @@ -69,7 +98,8 @@ void jpt_init_msg_header(opj_jpt_msg_header_t * header) { * Only parameters always present in message header * */ -void jpt_reinit_msg_header(opj_jpt_msg_header_t * header) { +void jpt_reinit_msg_header(opj_jpt_msg_header_t * header) +{ header->Id = 0; /* In-class Identifier */ header->last_byte = 0; /* Last byte information */ header->Msg_offset = 0; /* Message offset */ @@ -80,19 +110,31 @@ void jpt_reinit_msg_header(opj_jpt_msg_header_t * header) { * Read the message header for a JPP/JPT - stream * */ -void jpt_read_msg_header(opj_common_ptr cinfo, opj_cio_t *cio, opj_jpt_msg_header_t *header) { - unsigned char elmt, Class = 0, CSn = 0; - jpt_reinit_msg_header(header); +bool jpt_read_msg_header(opj_stream_private_t *cio, opj_jpt_msg_header_t *header, OPJ_UINT32 * p_nb_bytes_read, opj_event_mgr_t * p_manager) +{ + OPJ_BYTE elmt, Class = 0, CSn = 0; + OPJ_UINT32 l_nb_bytes_read = 0; + OPJ_UINT32 l_last_nb_bytes_read; + + jpt_reinit_msg_header(header); + /* ------------- */ /* VBAS : Bin-ID */ /* ------------- */ - elmt = cio_read(cio, 1); + if + (opj_stream_read_data(cio,&elmt,1,p_manager) != 1) + { + opj_event_msg(p_manager, EVT_ERROR, "Forbidden value encounter in message header !!\n"); + return false; + } + ++l_nb_bytes_read; /* See for Class and CSn */ - switch ((elmt >> 5) & 0x03) { + switch ((elmt >> 5) & 0x03) + { case 0: - opj_event_msg(cinfo, EVT_ERROR, "Forbidden value encounter in message header !!\n"); + opj_event_msg(p_manager, EVT_ERROR, "Error trying to read a byte of data!!!\n"); break; case 1: Class = 0; @@ -111,45 +153,97 @@ void jpt_read_msg_header(opj_common_ptr cinfo, opj_cio_t *cio, opj_jpt_msg_heade } /* see information on bits 'c' [p 10 : A.2.1 general, ISO/IEC FCD 15444-9] */ - if (((elmt >> 4) & 0x01) == 1) + if + (((elmt >> 4) & 0x01) == 1) + { header->last_byte = 1; + } /* In-class identifier */ header->Id |= (elmt & 0x0f); - if ((elmt >> 7) == 1) - header->Id = jpt_read_VBAS_info(cio, header->Id); + if + ((elmt >> 7) == 1) + { + l_last_nb_bytes_read = 0; + if + (! jpt_read_VBAS_info(cio, &l_last_nb_bytes_read, &(header->Id), p_manager)) + { + opj_event_msg(p_manager, EVT_ERROR, "Error trying to read a byte of data!!!\n"); + return false; + } + l_nb_bytes_read += l_last_nb_bytes_read; + } /* ------------ */ /* VBAS : Class */ /* ------------ */ - if (Class == 1) { + if (Class == 1) + { header->Class_Id = 0; - header->Class_Id = jpt_read_VBAS_info(cio, header->Class_Id); + l_last_nb_bytes_read = 0; + if + (! jpt_read_VBAS_info(cio, &l_last_nb_bytes_read, &(header->Class_Id), p_manager)) + { + opj_event_msg(p_manager, EVT_ERROR, "Error trying to read a byte of data!!!\n"); + return false; + } + l_nb_bytes_read += l_last_nb_bytes_read; } /* ---------- */ /* VBAS : CSn */ /* ---------- */ - if (CSn == 1) { + if (CSn == 1) + { header->CSn_Id = 0; - header->CSn_Id = jpt_read_VBAS_info(cio, header->CSn_Id); + l_last_nb_bytes_read = 0; + if + (! jpt_read_VBAS_info(cio, &l_last_nb_bytes_read, &(header->CSn_Id), p_manager)) + { + opj_event_msg(p_manager, EVT_ERROR, "Error trying to read a byte of data!!!\n"); + return false; + } + l_nb_bytes_read += l_last_nb_bytes_read; } /* ----------------- */ /* VBAS : Msg_offset */ /* ----------------- */ - header->Msg_offset = jpt_read_VBAS_info(cio, header->Msg_offset); + l_last_nb_bytes_read = 0; + if + (! jpt_read_VBAS_info(cio, &l_last_nb_bytes_read, &(header->Msg_offset), p_manager)) + { + opj_event_msg(p_manager, EVT_ERROR, "Error trying to read a byte of data!!!\n"); + return false; + } + l_nb_bytes_read += l_last_nb_bytes_read; /* ----------------- */ /* VBAS : Msg_length */ /* ----------------- */ - header->Msg_length = jpt_read_VBAS_info(cio, header->Msg_length); + l_last_nb_bytes_read = 0; + if + (! jpt_read_VBAS_info(cio, &l_last_nb_bytes_read, &(header->Msg_length), p_manager)) + { + opj_event_msg(p_manager, EVT_ERROR, "Error trying to read a byte of data!!!\n"); + return false; + } + l_nb_bytes_read += l_last_nb_bytes_read; /* ---------- */ /* VBAS : Aux */ /* ---------- */ - if ((header->Class_Id & 0x01) == 1) { + if ((header->Class_Id & 0x01) == 1) + { header->Layer_nb = 0; - header->Layer_nb = jpt_read_VBAS_info(cio, header->Layer_nb); + if + (! jpt_read_VBAS_info(cio, &l_last_nb_bytes_read, &(header->Layer_nb), p_manager)) + { + opj_event_msg(p_manager, EVT_ERROR, "Error trying to read a byte of data!!!\n"); + return false; + } + l_nb_bytes_read += l_last_nb_bytes_read; } + * p_nb_bytes_read = l_nb_bytes_read; + return true; } diff --git a/libopenjpeg/jpt.h b/libopenjpeg/jpt.h index eb01f98e..22af2c2a 100644 --- a/libopenjpeg/jpt.h +++ b/libopenjpeg/jpt.h @@ -3,6 +3,7 @@ * Copyright (c) 2002-2007, Professor Benoit Macq * Copyright (c) 2002-2003, Yannick Verschueren * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,25 +36,28 @@ JPT-stream functions are implemented in J2K.C. */ - +#include "openjpeg.h" +struct opj_stream_private; +struct opj_event_mgr; /** Message Header JPT stream structure */ -typedef struct opj_jpt_msg_header { +typedef struct opj_jpt_msg_header +{ /** In-class Identifier */ - unsigned int Id; + OPJ_UINT32 Id; /** Last byte information */ - unsigned int last_byte; + OPJ_UINT32 last_byte; /** Class Identifier */ - unsigned int Class_Id; + OPJ_UINT32 Class_Id; /** CSn : index identifier */ - unsigned int CSn_Id; + OPJ_UINT32 CSn_Id; /** Message offset */ - unsigned int Msg_offset; + OPJ_UINT32 Msg_offset; /** Message length */ - unsigned int Msg_length; + OPJ_UINT32 Msg_length; /** Auxiliary for JPP case */ - unsigned int Layer_nb; + OPJ_UINT32 Layer_nb; } opj_jpt_msg_header_t; /* ----------------------------------------------------------------------- */ @@ -65,11 +69,15 @@ Initialize the value of the message header structure void jpt_init_msg_header(opj_jpt_msg_header_t * header); /** -Read the message header for a JPP/JPT - stream -@param cinfo Codec context info -@param cio CIO handle -@param header Message header structure + * Read the message header for a JPP/JPT - stream + * @param p_cio stream handle + * @param header JPT Message header structure + * @param p_manager user event manager to display nice messages. */ -void jpt_read_msg_header(opj_common_ptr cinfo, opj_cio_t *cio, opj_jpt_msg_header_t *header); +bool jpt_read_msg_header( + struct opj_stream_private * p_cio, + opj_jpt_msg_header_t * p_header, + OPJ_UINT32 * p_nb_bytes_read, + struct opj_event_mgr * p_manager); #endif diff --git a/libopenjpeg/mct.c b/libopenjpeg/mct.c index ca21744f..1c7565de 100644 --- a/libopenjpeg/mct.c +++ b/libopenjpeg/mct.c @@ -5,6 +5,7 @@ * Copyright (c) 2002-2003, Yannick Verschueren * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,35 +30,51 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "opj_includes.h" +#include "mct.h" +#include "fix.h" +#include "opj_malloc.h" /* <summary> */ /* This table contains the norms of the basis function of the reversible MCT. */ /* </summary> */ -static const double mct_norms[3] = { 1.732, .8292, .8292 }; +static const OPJ_FLOAT64 mct_norms[3] = { 1.732, .8292, .8292 }; /* <summary> */ /* This table contains the norms of the basis function of the irreversible MCT. */ /* </summary> */ -static const double mct_norms_real[3] = { 1.732, 1.805, 1.573 }; +static const OPJ_FLOAT64 mct_norms_real[3] = { 1.732, 1.805, 1.573 }; + + + +const OPJ_FLOAT64 * get_mct_norms () +{ + return mct_norms; +} + +const OPJ_FLOAT64 * get_mct_norms_real () +{ + return mct_norms_real; +} + + /* <summary> */ /* Foward reversible MCT. */ /* </summary> */ void mct_encode( - int* restrict c0, - int* restrict c1, - int* restrict c2, - int n) + OPJ_INT32* restrict c0, + OPJ_INT32* restrict c1, + OPJ_INT32* restrict c2, + OPJ_UINT32 n) { - int i; + OPJ_UINT32 i; for(i = 0; i < n; ++i) { - int r = c0[i]; - int g = c1[i]; - int b = c2[i]; - int y = (r + (g * 2) + b) >> 2; - int u = b - g; - int v = r - g; + OPJ_INT32 r = c0[i]; + OPJ_INT32 g = c1[i]; + OPJ_INT32 b = c2[i]; + OPJ_INT32 y = (r + (g * 2) + b) >> 2; + OPJ_INT32 u = b - g; + OPJ_INT32 v = r - g; c0[i] = y; c1[i] = u; c2[i] = v; @@ -68,19 +85,19 @@ void mct_encode( /* Inverse reversible MCT. */ /* </summary> */ void mct_decode( - int* restrict c0, - int* restrict c1, - int* restrict c2, - int n) + OPJ_INT32* restrict c0, + OPJ_INT32* restrict c1, + OPJ_INT32* restrict c2, + OPJ_UINT32 n) { - int i; + OPJ_UINT32 i; for (i = 0; i < n; ++i) { - int y = c0[i]; - int u = c1[i]; - int v = c2[i]; - int g = y - ((u + v) >> 2); - int r = v + g; - int b = u + g; + OPJ_INT32 y = c0[i]; + OPJ_INT32 u = c1[i]; + OPJ_INT32 v = c2[i]; + OPJ_INT32 g = y - ((u + v) >> 2); + OPJ_INT32 r = v + g; + OPJ_INT32 b = u + g; c0[i] = r; c1[i] = g; c2[i] = b; @@ -90,7 +107,7 @@ void mct_decode( /* <summary> */ /* Get norm of basis function of reversible MCT. */ /* </summary> */ -double mct_getnorm(int compno) { +OPJ_FLOAT64 mct_getnorm(OPJ_UINT32 compno) { return mct_norms[compno]; } @@ -98,19 +115,19 @@ double mct_getnorm(int compno) { /* Foward irreversible MCT. */ /* </summary> */ void mct_encode_real( - int* restrict c0, - int* restrict c1, - int* restrict c2, - int n) + OPJ_INT32* restrict c0, + OPJ_INT32* restrict c1, + OPJ_INT32* restrict c2, + OPJ_UINT32 n) { - int i; + OPJ_UINT32 i; for(i = 0; i < n; ++i) { - int r = c0[i]; - int g = c1[i]; - int b = c2[i]; - int y = fix_mul(r, 2449) + fix_mul(g, 4809) + fix_mul(b, 934); - int u = -fix_mul(r, 1382) - fix_mul(g, 2714) + fix_mul(b, 4096); - int v = fix_mul(r, 4096) - fix_mul(g, 3430) - fix_mul(b, 666); + OPJ_INT32 r = c0[i]; + OPJ_INT32 g = c1[i]; + OPJ_INT32 b = c2[i]; + OPJ_INT32 y = fix_mul(r, 2449) + fix_mul(g, 4809) + fix_mul(b, 934); + OPJ_INT32 u = -fix_mul(r, 1382) - fix_mul(g, 2714) + fix_mul(b, 4096); + OPJ_INT32 v = fix_mul(r, 4096) - fix_mul(g, 3430) - fix_mul(b, 666); c0[i] = y; c1[i] = u; c2[i] = v; @@ -121,19 +138,19 @@ void mct_encode_real( /* Inverse irreversible MCT. */ /* </summary> */ void mct_decode_real( - float* restrict c0, - float* restrict c1, - float* restrict c2, - int n) + OPJ_FLOAT32* restrict c0, + OPJ_FLOAT32* restrict c1, + OPJ_FLOAT32* restrict c2, + OPJ_UINT32 n) { - int i; + OPJ_UINT32 i; for(i = 0; i < n; ++i) { - float y = c0[i]; - float u = c1[i]; - float v = c2[i]; - float r = y + (v * 1.402f); - float g = y - (u * 0.34413f) - (v * (0.71414f)); - float b = y + (u * 1.772f); + OPJ_FLOAT32 y = c0[i]; + OPJ_FLOAT32 u = c1[i]; + OPJ_FLOAT32 v = c2[i]; + OPJ_FLOAT32 r = y + (v * 1.402f); + OPJ_FLOAT32 g = y - (u * 0.34413f) - (v * (0.71414f)); + OPJ_FLOAT32 b = y + (u * 1.772f); c0[i] = r; c1[i] = g; c2[i] = b; @@ -143,6 +160,145 @@ void mct_decode_real( /* <summary> */ /* Get norm of basis function of irreversible MCT. */ /* </summary> */ -double mct_getnorm_real(int compno) { +OPJ_FLOAT64 mct_getnorm_real(OPJ_UINT32 compno) { return mct_norms_real[compno]; } + +bool mct_encode_custom( + // MCT data + OPJ_BYTE * pCodingdata, + // size of components + OPJ_UINT32 n, + // components + OPJ_BYTE ** pData, + // nb of components (i.e. size of pData) + OPJ_UINT32 pNbComp, + // tells if the data is signed + OPJ_UINT32 isSigned) +{ + OPJ_FLOAT32 * lMct = (OPJ_FLOAT32 *) pCodingdata; + OPJ_UINT32 i; + OPJ_UINT32 j; + OPJ_UINT32 k; + OPJ_UINT32 lNbMatCoeff = pNbComp * pNbComp; + OPJ_INT32 * lCurrentData = 00; + OPJ_INT32 * lCurrentMatrix = 00; + OPJ_INT32 ** lData = (OPJ_INT32 **) pData; + OPJ_UINT32 lMultiplicator = 1 << 13; + OPJ_INT32 * lMctPtr; + + lCurrentData = (OPJ_INT32 *) opj_malloc((pNbComp + lNbMatCoeff) * sizeof(OPJ_INT32)); + if + (! lCurrentData) + { + return false; + } + lCurrentMatrix = lCurrentData + pNbComp; + for + (i =0;i<lNbMatCoeff;++i) + { + lCurrentMatrix[i] = (OPJ_INT32) (*(lMct++) * lMultiplicator); + } + for + (i = 0; i < n; ++i) + { + lMctPtr = lCurrentMatrix; + for + (j=0;j<pNbComp;++j) + { + lCurrentData[j] = (*(lData[j])); + } + for + (j=0;j<pNbComp;++j) + { + *(lData[j]) = 0; + for + (k=0;k<pNbComp;++k) + { + *(lData[j]) += fix_mul(*lMctPtr, lCurrentData[k]); + ++lMctPtr; + } + ++lData[j]; + } + } + opj_free(lCurrentData); + return true; +} + +bool mct_decode_custom( + // MCT data + OPJ_BYTE * pDecodingData, + // size of components + OPJ_UINT32 n, + // components + OPJ_BYTE ** pData, + // nb of components (i.e. size of pData) + OPJ_UINT32 pNbComp, + // tells if the data is signed + OPJ_UINT32 isSigned) +{ + OPJ_FLOAT32 * lMct; + OPJ_UINT32 i; + OPJ_UINT32 j; + OPJ_UINT32 k; + + OPJ_FLOAT32 * lCurrentData = 00; + OPJ_FLOAT32 * lCurrentResult = 00; + OPJ_FLOAT32 ** lData = (OPJ_FLOAT32 **) pData; + + lCurrentData = (OPJ_FLOAT32 *) opj_malloc (2 * pNbComp * sizeof(OPJ_FLOAT32)); + if + (! lCurrentData) + { + return false; + } + lCurrentResult = lCurrentData + pNbComp; + + for + (i = 0; i < n; ++i) + { + lMct = (OPJ_FLOAT32 *) pDecodingData; + for + (j=0;j<pNbComp;++j) + { + lCurrentData[j] = (OPJ_FLOAT32) (*(lData[j])); + } + for + (j=0;j<pNbComp;++j) + { + lCurrentResult[j] = 0; + for + (k=0;k<pNbComp;++k) + { + lCurrentResult[j] += *(lMct++) * lCurrentData[k]; + } + *(lData[j]++) = (OPJ_FLOAT32) (lCurrentResult[j]); + } + } + opj_free(lCurrentData); + return true; +} + +void opj_calculate_norms(OPJ_FLOAT64 * pNorms,OPJ_UINT32 pNbComps,OPJ_FLOAT32 * pMatrix) +{ + OPJ_UINT32 i,j,lIndex; + OPJ_FLOAT32 lCurrentValue; + OPJ_FLOAT64 * lNorms = (OPJ_FLOAT64 *) pNorms; + OPJ_FLOAT32 * lMatrix = (OPJ_FLOAT32 *) pMatrix; + + for + (i=0;i<pNbComps;++i) + { + lNorms[i] = 0; + lIndex = i; + for + (j=0;j<pNbComps;++j) + { + lCurrentValue = lMatrix[lIndex]; + lIndex += pNbComps; + lNorms[i] += lCurrentValue * lCurrentValue; + } + lNorms[i] = sqrt(lNorms[i]); + } +} + diff --git a/libopenjpeg/mct.h b/libopenjpeg/mct.h index 84e3f8ad..f6497efa 100644 --- a/libopenjpeg/mct.h +++ b/libopenjpeg/mct.h @@ -5,6 +5,7 @@ * Copyright (c) 2002-2003, Yannick Verschueren * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -38,7 +39,7 @@ The functions in MCT.C have for goal to realize reversible and irreversible multicomponent transform. The functions in MCT.C are used by some function in TCD.C. */ - +#include "openjpeg.h" /** @defgroup MCT MCT - Implementation of a multi-component transform */ /*@{*/ @@ -52,7 +53,7 @@ Apply a reversible multi-component transform to an image @param c2 Samples blue component @param n Number of samples for each component */ -void mct_encode(int *c0, int *c1, int *c2, int n); +void mct_encode(OPJ_INT32 *c0, OPJ_INT32 *c1, OPJ_INT32 *c2, OPJ_UINT32 n); /** Apply a reversible multi-component inverse transform to an image @param c0 Samples for luminance component @@ -60,13 +61,13 @@ Apply a reversible multi-component inverse transform to an image @param c2 Samples for blue chrominance component @param n Number of samples for each component */ -void mct_decode(int *c0, int *c1, int *c2, int n); +void mct_decode(OPJ_INT32 *c0, OPJ_INT32 *c1, OPJ_INT32 *c2, OPJ_UINT32 n); /** Get norm of the basis function used for the reversible multi-component transform @param compno Number of the component (0->Y, 1->U, 2->V) @return */ -double mct_getnorm(int compno); +OPJ_FLOAT64 mct_getnorm(OPJ_UINT32 compno); /** Apply an irreversible multi-component transform to an image @@ -75,7 +76,7 @@ Apply an irreversible multi-component transform to an image @param c2 Samples blue component @param n Number of samples for each component */ -void mct_encode_real(int *c0, int *c1, int *c2, int n); +void mct_encode_real(OPJ_INT32 *c0, OPJ_INT32 *c1, OPJ_INT32 *c2, OPJ_UINT32 n); /** Apply an irreversible multi-component inverse transform to an image @param c0 Samples for luminance component @@ -83,13 +84,44 @@ Apply an irreversible multi-component inverse transform to an image @param c2 Samples for blue chrominance component @param n Number of samples for each component */ -void mct_decode_real(float* c0, float* c1, float* c2, int n); +void mct_decode_real(OPJ_FLOAT32* c0, OPJ_FLOAT32* c1, OPJ_FLOAT32* c2, OPJ_UINT32 n); /** Get norm of the basis function used for the irreversible multi-component transform @param compno Number of the component (0->Y, 1->U, 2->V) @return */ -double mct_getnorm_real(int compno); +OPJ_FLOAT64 mct_getnorm_real(OPJ_UINT32 compno); + +bool mct_encode_custom( + // MCT data + OPJ_BYTE * p_coding_data, + // size of components + OPJ_UINT32 n, + // components + OPJ_BYTE ** p_data, + // nb of components (i.e. size of p_data) + OPJ_UINT32 p_nb_comp, + // tells if the data is signed + OPJ_UINT32 is_signed); + +bool mct_decode_custom( + // MCT data + OPJ_BYTE * pDecodingData, + // size of components + OPJ_UINT32 n, + // components + OPJ_BYTE ** pData, + // nb of components (i.e. size of pData) + OPJ_UINT32 pNbComp, + // tells if the data is signed + OPJ_UINT32 isSigned); + +void opj_calculate_norms(OPJ_FLOAT64 * pNorms,OPJ_UINT32 p_nb_comps,OPJ_FLOAT32 * pMatrix); + +const OPJ_FLOAT64 * get_mct_norms (); +const OPJ_FLOAT64 * get_mct_norms_real (); + + /* ----------------------------------------------------------------------- */ /*@}*/ diff --git a/libopenjpeg/mqc.c b/libopenjpeg/mqc.c index 9aa9d2c2..e6cfd325 100644 --- a/libopenjpeg/mqc.c +++ b/libopenjpeg/mqc.c @@ -5,6 +5,7 @@ * Copyright (c) 2002-2003, Yannick Verschueren * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,7 +30,9 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "opj_includes.h" +#include "mqc.h" +#include "t1.h" +#include "opj_malloc.h" /** @defgroup MQC MQC - Implementation of an MQ-Coder */ /*@{*/ @@ -68,13 +71,13 @@ FIXME: documentation ??? @param mqc MQC handle @return */ -static int mqc_mpsexchange(opj_mqc_t *mqc); +static OPJ_INT32 mqc_mpsexchange(opj_mqc_t *mqc); /** FIXME: documentation ??? @param mqc MQC handle @return */ -static int mqc_lpsexchange(opj_mqc_t *mqc); +static OPJ_INT32 mqc_lpsexchange(opj_mqc_t *mqc); /** Input a byte @param mqc MQC handle @@ -264,15 +267,15 @@ static void mqc_codelps(opj_mqc_t *mqc) { } static void mqc_setbits(opj_mqc_t *mqc) { - unsigned int tempc = mqc->c + mqc->a; + OPJ_UINT32 tempc = mqc->c + mqc->a; mqc->c |= 0xffff; if (mqc->c >= tempc) { mqc->c -= 0x8000; } } -static int mqc_mpsexchange(opj_mqc_t *mqc) { - int d; +static OPJ_INT32 mqc_mpsexchange(opj_mqc_t *mqc) { + OPJ_INT32 d; if (mqc->a < (*mqc->curctx)->qeval) { d = 1 - (*mqc->curctx)->mps; *mqc->curctx = (*mqc->curctx)->nlps; @@ -284,8 +287,8 @@ static int mqc_mpsexchange(opj_mqc_t *mqc) { return d; } -static int mqc_lpsexchange(opj_mqc_t *mqc) { - int d; +static OPJ_INT32 mqc_lpsexchange(opj_mqc_t *mqc) { + OPJ_INT32 d; if (mqc->a < (*mqc->curctx)->qeval) { mqc->a = (*mqc->curctx)->qeval; d = (*mqc->curctx)->mps; @@ -301,7 +304,7 @@ static int mqc_lpsexchange(opj_mqc_t *mqc) { static void mqc_bytein(opj_mqc_t *mqc) { if (mqc->bp != mqc->end) { - unsigned int c; + OPJ_UINT32 c; if (mqc->bp + 1 != mqc->end) { c = *(mqc->bp + 1); } else { @@ -350,28 +353,31 @@ opj_mqc_t* mqc_create(void) { } void mqc_destroy(opj_mqc_t *mqc) { - if(mqc) { + if + (mqc) + { opj_free(mqc); } } -int mqc_numbytes(opj_mqc_t *mqc) { +OPJ_UINT32 mqc_numbytes(opj_mqc_t *mqc) { return mqc->bp - mqc->start; } -void mqc_init_enc(opj_mqc_t *mqc, unsigned char *bp) { +void mqc_init_enc(opj_mqc_t *mqc, OPJ_BYTE *bp) { mqc_setcurctx(mqc, 0); mqc->a = 0x8000; mqc->c = 0; mqc->bp = bp - 1; + *(mqc->bp) = 0; mqc->ct = 12; - if (*mqc->bp == 0xff) { + /*if (*mqc->bp == 0xff) { mqc->ct = 13; - } + }*/ mqc->start = bp; } -void mqc_encode(opj_mqc_t *mqc, int d) { +void mqc_encode(opj_mqc_t *mqc, OPJ_UINT32 d) { if ((*mqc->curctx)->mps == d) { mqc_codemps(mqc); } else { @@ -399,7 +405,7 @@ void mqc_bypass_init_enc(opj_mqc_t *mqc) { } */ } -void mqc_bypass_enc(opj_mqc_t *mqc, int d) { +void mqc_bypass_enc(opj_mqc_t *mqc, OPJ_UINT32 d) { mqc->ct--; mqc->c = mqc->c + (d << mqc->ct); if (mqc->ct == 0) { @@ -413,8 +419,8 @@ void mqc_bypass_enc(opj_mqc_t *mqc, int d) { } } -int mqc_bypass_flush_enc(opj_mqc_t *mqc) { - unsigned char bit_padding; +OPJ_UINT32 mqc_bypass_flush_enc(opj_mqc_t *mqc) { + OPJ_BYTE bit_padding; bit_padding = 0; @@ -440,11 +446,11 @@ void mqc_reset_enc(opj_mqc_t *mqc) { mqc_setstate(mqc, T1_CTXNO_ZC, 0, 4); } -int mqc_restart_enc(opj_mqc_t *mqc) { - int correction = 1; +OPJ_UINT32 mqc_restart_enc(opj_mqc_t *mqc) { + OPJ_UINT32 correction = 1; /* <flush part> */ - int n = 27 - 15 - mqc->ct; + OPJ_INT32 n = 27 - 15 - mqc->ct; mqc->c <<= mqc->ct; while (n > 0) { mqc_byteout(mqc); @@ -469,7 +475,7 @@ void mqc_restart_init_enc(opj_mqc_t *mqc) { } void mqc_erterm_enc(opj_mqc_t *mqc) { - int k = 11 - mqc->ct + 1; + OPJ_INT32 k = 11 - mqc->ct + 1; while (k > 0) { mqc->c <<= mqc->ct; @@ -484,7 +490,7 @@ void mqc_erterm_enc(opj_mqc_t *mqc) { } void mqc_segmark_enc(opj_mqc_t *mqc) { - int i; + OPJ_UINT32 i; mqc_setcurctx(mqc, 18); for (i = 1; i < 5; i++) { @@ -492,7 +498,7 @@ void mqc_segmark_enc(opj_mqc_t *mqc) { } } -void mqc_init_dec(opj_mqc_t *mqc, unsigned char *bp, int len) { +void mqc_init_dec(opj_mqc_t *mqc, OPJ_BYTE *bp, OPJ_UINT32 len) { mqc_setcurctx(mqc, 0); mqc->start = bp; mqc->end = bp + len; @@ -505,8 +511,8 @@ void mqc_init_dec(opj_mqc_t *mqc, unsigned char *bp, int len) { mqc->a = 0x8000; } -int mqc_decode(opj_mqc_t *mqc) { - int d; +OPJ_UINT32 mqc_decode(opj_mqc_t *mqc) { + OPJ_INT32 d; mqc->a -= (*mqc->curctx)->qeval; if ((mqc->c >> 16) < (*mqc->curctx)->qeval) { d = mqc_lpsexchange(mqc); @@ -521,17 +527,17 @@ int mqc_decode(opj_mqc_t *mqc) { } } - return d; + return (OPJ_UINT32)d; } void mqc_resetstates(opj_mqc_t *mqc) { - int i; + OPJ_UINT32 i; for (i = 0; i < MQC_NUMCTXS; i++) { mqc->ctxs[i] = mqc_states; } } -void mqc_setstate(opj_mqc_t *mqc, int ctxno, int msb, int prob) { +void mqc_setstate(opj_mqc_t *mqc, OPJ_UINT32 ctxno, OPJ_UINT32 msb, OPJ_INT32 prob) { mqc->ctxs[ctxno] = &mqc_states[msb + (prob << 1)]; } diff --git a/libopenjpeg/mqc.h b/libopenjpeg/mqc.h index 8cc8c934..93d3b943 100644 --- a/libopenjpeg/mqc.h +++ b/libopenjpeg/mqc.h @@ -5,6 +5,7 @@ * Copyright (c) 2002-2003, Yannick Verschueren * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -38,7 +39,7 @@ The functions in MQC.C have for goal to realize the MQ-coder operations. The functions in MQC.C are used by some function in T1.C. */ - +#include "openjpeg.h" /** @defgroup MQC MQC - Implementation of an MQ-Coder */ /*@{*/ @@ -47,27 +48,27 @@ This struct defines the state of a context. */ typedef struct opj_mqc_state { /** the probability of the Least Probable Symbol (0.75->0x8000, 1.5->0xffff) */ - unsigned int qeval; + OPJ_UINT32 qeval; /** the Most Probable Symbol (0 or 1) */ - int mps; + OPJ_INT32 mps; /** next state if the next encoded symbol is the MPS */ struct opj_mqc_state *nmps; /** next state if the next encoded symbol is the LPS */ struct opj_mqc_state *nlps; } opj_mqc_state_t; -#define MQC_NUMCTXS 19 +#define MQC_NUMCTXS 32 /** MQ coder */ typedef struct opj_mqc { - unsigned int c; - unsigned int a; - unsigned int ct; - unsigned char *bp; - unsigned char *start; - unsigned char *end; + OPJ_UINT32 c; + OPJ_UINT32 a; + OPJ_UINT32 ct; + OPJ_BYTE *bp; + OPJ_BYTE *start; + OPJ_BYTE *end; opj_mqc_state_t *ctxs[MQC_NUMCTXS]; opj_mqc_state_t **curctx; } opj_mqc_t; @@ -90,7 +91,7 @@ Return the number of bytes written/read since initialisation @param mqc MQC handle @return Returns the number of bytes already encoded */ -int mqc_numbytes(opj_mqc_t *mqc); +OPJ_UINT32 mqc_numbytes(opj_mqc_t *mqc); /** Reset the states of all the context of the coder/decoder (each context is set to a state where 0 and 1 are more or less equiprobable) @@ -104,25 +105,25 @@ Set the state of a particular context @param msb The MSB of the new state of the context @param prob Number that identifies the probability of the symbols for the new state of the context */ -void mqc_setstate(opj_mqc_t *mqc, int ctxno, int msb, int prob); +void mqc_setstate(opj_mqc_t *mqc, OPJ_UINT32 ctxno, OPJ_UINT32 msb, OPJ_INT32 prob); /** Initialize the encoder @param mqc MQC handle @param bp Pointer to the start of the buffer where the bytes will be written */ -void mqc_init_enc(opj_mqc_t *mqc, unsigned char *bp); +void mqc_init_enc(opj_mqc_t *mqc, OPJ_BYTE *bp); /** Set the current context used for coding/decoding @param mqc MQC handle @param ctxno Number that identifies the context */ -#define mqc_setcurctx(mqc, ctxno) (mqc)->curctx = &(mqc)->ctxs[(int)(ctxno)] +#define mqc_setcurctx(mqc, ctxno) (mqc)->curctx = &(mqc)->ctxs[(OPJ_UINT32)(ctxno)] /** Encode a symbol using the MQ-coder @param mqc MQC handle @param d The symbol to be encoded (0 or 1) */ -void mqc_encode(opj_mqc_t *mqc, int d); +void mqc_encode(opj_mqc_t *mqc, OPJ_UINT32 d); /** Flush the encoder, so that all remaining data is written @param mqc MQC handle @@ -142,14 +143,14 @@ JPEG 2000 p 505. @param mqc MQC handle @param d The symbol to be encoded (0 or 1) */ -void mqc_bypass_enc(opj_mqc_t *mqc, int d); +void mqc_bypass_enc(opj_mqc_t *mqc, OPJ_UINT32 d); /** BYPASS mode switch, flush operation <h2>Not fully implemented and tested !!</h2> @param mqc MQC handle @return Returns 1 (always) */ -int mqc_bypass_flush_enc(opj_mqc_t *mqc); +OPJ_UINT32 mqc_bypass_flush_enc(opj_mqc_t *mqc); /** RESET mode switch @param mqc MQC handle @@ -160,7 +161,7 @@ RESTART mode switch (TERMALL) @param mqc MQC handle @return Returns 1 (always) */ -int mqc_restart_enc(opj_mqc_t *mqc); +OPJ_UINT32 mqc_restart_enc(opj_mqc_t *mqc); /** RESTART mode switch (TERMALL) reinitialisation @param mqc MQC handle @@ -182,13 +183,13 @@ Initialize the decoder @param bp Pointer to the start of the buffer from which the bytes will be read @param len Length of the input buffer */ -void mqc_init_dec(opj_mqc_t *mqc, unsigned char *bp, int len); +void mqc_init_dec(opj_mqc_t *mqc, OPJ_BYTE *bp, OPJ_UINT32 len); /** Decode a symbol @param mqc MQC handle @return Returns the decoded symbol (0 or 1) */ -int mqc_decode(opj_mqc_t *mqc); +OPJ_UINT32 mqc_decode(opj_mqc_t *mqc); /* ----------------------------------------------------------------------- */ /*@}*/ diff --git a/libopenjpeg/openjpeg.c b/libopenjpeg/openjpeg.c index 88d44fd0..574b5135 100644 --- a/libopenjpeg/openjpeg.c +++ b/libopenjpeg/openjpeg.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,7 +29,124 @@ #include <windows.h> #endif /* WIN32 */ -#include "opj_includes.h" +#include "openjpeg.h" +#include "opj_malloc.h" +#include "j2k.h" +#include "jp2.h" +#include "event.h" +#include "cio.h" + +typedef struct opj_decompression +{ + bool (* opj_read_header) ( + void *p_codec, + opj_image_t **, + 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, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager); + opj_image_t* (* opj_decode) (void * p_codec, struct opj_stream_private *p_cio, struct opj_event_mgr * p_manager); + bool (*opj_read_tile_header)( + void * p_codec, + 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, + bool * p_should_go_on, + struct opj_stream_private *p_cio, + struct opj_event_mgr * p_manager); + bool (*opj_decode_tile_data)(void * p_codec,OPJ_UINT32 p_tile_index,OPJ_BYTE * p_data,OPJ_UINT32 p_data_size,struct opj_stream_private *p_cio,struct opj_event_mgr * p_manager); + bool (* opj_end_decompress) (void *p_codec,struct opj_stream_private *cio,struct opj_event_mgr * p_manager); + void (* opj_destroy) (void * p_codec); + void (*opj_setup_decoder) (void * p_codec,opj_dparameters_t * p_param); + bool (*opj_set_decode_area) (void * p_codec,OPJ_INT32 p_start_x,OPJ_INT32 p_end_x,OPJ_INT32 p_start_y,OPJ_INT32 p_end_y,struct opj_event_mgr * p_manager); + + +}opj_decompression_t; + +typedef struct opj_compression +{ + bool (* opj_start_compress) (void *p_codec,struct opj_stream_private *cio,struct opj_image * p_image, struct opj_event_mgr * p_manager); + bool (* opj_encode) (void * p_codec, struct opj_stream_private *p_cio, struct opj_event_mgr * p_manager); + bool (* opj_write_tile) (void * p_codec,OPJ_UINT32 p_tile_index,OPJ_BYTE * p_data,OPJ_UINT32 p_data_size,struct opj_stream_private * p_cio,struct opj_event_mgr * p_manager); + bool (* opj_end_compress) (void * p_codec, struct opj_stream_private *p_cio, struct opj_event_mgr * p_manager); + void (* opj_destroy) (void * p_codec); + void (*opj_setup_encoder) (void * p_codec,opj_cparameters_t * p_param,struct opj_image * p_image, struct opj_event_mgr * p_manager); + +}opj_compression_t; + + + +typedef struct opj_codec_private +{ + union + { /* code-blocks informations */ + opj_decompression_t m_decompression; + opj_compression_t m_compression; + } m_codec_data; + void * m_codec; + opj_event_mgr_t m_event_mgr; + unsigned is_decompressor : 1; +} +opj_codec_private_t; + + + +/** + * Default callback function. + * Do nothing. + */ +void opj_default_callback (const char *msg, void *client_data) +{ +} + +void set_default_event_handler(opj_event_mgr_t * p_manager) +{ + 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; +} + +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 false; + } + return true; +} /* ---------------------------------------------------------------------- */ #ifdef WIN32 @@ -57,56 +175,133 @@ const char* OPJ_CALLCONV opj_version(void) { return OPENJPEG_VERSION; } -opj_dinfo_t* OPJ_CALLCONV opj_create_decompress(OPJ_CODEC_FORMAT format) { - opj_dinfo_t *dinfo = (opj_dinfo_t*)opj_calloc(1, sizeof(opj_dinfo_t)); - if(!dinfo) return NULL; - dinfo->is_decompressor = true; - switch(format) { +opj_codec_t* OPJ_CALLCONV opj_create_decompress(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: - case CODEC_JPT: - /* get a J2K decoder handle */ - dinfo->j2k_handle = (void*)j2k_create_decompress((opj_common_ptr)dinfo); - if(!dinfo->j2k_handle) { - opj_free(dinfo); - return NULL; + 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 = (bool (*) (void *,struct opj_stream_private *,struct opj_event_mgr *))j2k_end_decompress; + l_info->m_codec_data.m_decompression.opj_read_header = (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 = (bool (*) ( + void *, + OPJ_UINT32*, + OPJ_UINT32*, + OPJ_INT32 * , + OPJ_INT32 * , + OPJ_INT32 * , + OPJ_INT32 * , + OPJ_UINT32 * , + bool *, + struct opj_stream_private *, + struct opj_event_mgr * )) j2k_read_tile_header; + l_info->m_codec_data.m_decompression.opj_decode_tile_data = (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 = (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(); + if + (! l_info->m_codec) + { + opj_free(l_info); + return 00; } break; + case CODEC_JP2: /* get a JP2 decoder handle */ - dinfo->jp2_handle = (void*)jp2_create_decompress((opj_common_ptr)dinfo); - if(!dinfo->jp2_handle) { - opj_free(dinfo); - return NULL; + l_info->m_codec_data.m_decompression.opj_decode = (opj_image_t* (*) (void *, struct opj_stream_private *, struct opj_event_mgr * ))jp2_decode; + l_info->m_codec_data.m_decompression.opj_end_decompress = (bool (*) (void *,struct opj_stream_private *,struct opj_event_mgr *)) jp2_end_decompress; + l_info->m_codec_data.m_decompression.opj_read_header = (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 = ( + bool (*) ( + void *, + OPJ_UINT32*, + OPJ_UINT32*, + OPJ_INT32*, + OPJ_INT32*, + OPJ_INT32 * , + OPJ_INT32 * , + OPJ_UINT32 * , + bool *, + struct opj_stream_private *, + struct opj_event_mgr * )) jp2_read_tile_header; + + l_info->m_codec_data.m_decompression.opj_decode_tile_data = (bool (*) (void *,OPJ_UINT32,OPJ_BYTE*,OPJ_UINT32,struct opj_stream_private *, struct opj_event_mgr * )) 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 = (bool (*) (void *,OPJ_INT32,OPJ_INT32,OPJ_INT32,OPJ_INT32, struct opj_event_mgr * )) jp2_set_decode_area; + + + l_info->m_codec = jp2_create(true); + if + (! l_info->m_codec) + { + opj_free(l_info); + return 00; } break; case CODEC_UNKNOWN: + case CODEC_JPT: default: - opj_free(dinfo); - return NULL; + opj_free(l_info); + return 00; } - - dinfo->codec_format = format; - - return dinfo; + 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 */ - switch(dinfo->codec_format) { - case CODEC_J2K: - case CODEC_JPT: - j2k_destroy_decompress((opj_j2k_t*)dinfo->j2k_handle); - break; - case CODEC_JP2: - jp2_destroy_decompress((opj_jp2_t*)dinfo->jp2_handle); - break; - case CODEC_UNKNOWN: - default: - break; +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); } - /* destroy the decompressor */ - opj_free(dinfo); + l_info->m_codec = 00; + opj_free(l_info); } } @@ -116,7 +311,6 @@ void OPJ_CALLCONV opj_set_default_decoder_parameters(opj_dparameters_t *paramete /* default decoding parameters */ parameters->cp_layer = 0; parameters->cp_reduce = 0; - parameters->cp_limit_decoding = NO_LIMITATION; parameters->decod_format = -1; parameters->cod_format = -1; @@ -130,95 +324,317 @@ void OPJ_CALLCONV opj_set_default_decoder_parameters(opj_dparameters_t *paramete } } -void OPJ_CALLCONV opj_setup_decoder(opj_dinfo_t *dinfo, opj_dparameters_t *parameters) { - if(dinfo && parameters) { - switch(dinfo->codec_format) { - case CODEC_J2K: - case CODEC_JPT: - j2k_setup_decoder((opj_j2k_t*)dinfo->j2k_handle, parameters); - break; - case CODEC_JP2: - jp2_setup_decoder((opj_jp2_t*)dinfo->jp2_handle, parameters); - break; - case CODEC_UNKNOWN: - default: - break; +bool OPJ_CALLCONV opj_setup_decoder(opj_codec_t *p_info, opj_dparameters_t *parameters) { + if + (p_info && parameters) + { + opj_codec_private_t * l_info = (opj_codec_private_t *) p_info; + if + (! l_info->is_decompressor) + { + return false; } + l_info->m_codec_data.m_decompression.opj_setup_decoder(l_info->m_codec,parameters); + return true; } + return false; } -opj_image_t* OPJ_CALLCONV opj_decode(opj_dinfo_t *dinfo, opj_cio_t *cio) { - return opj_decode_with_info(dinfo, cio, NULL); +opj_image_t* OPJ_CALLCONV opj_decode(opj_codec_t *p_info, opj_stream_t *cio) +{ + if + (p_info && cio) + { + opj_codec_private_t * l_info = (opj_codec_private_t *) p_info; + opj_stream_private_t * l_cio = (opj_stream_private_t *) cio; + if + (! l_info->is_decompressor) + { + return 00; + } + return l_info->m_codec_data.m_decompression.opj_decode(l_info->m_codec,l_cio,&(l_info->m_event_mgr)); + } + return 00; } -opj_image_t* OPJ_CALLCONV opj_decode_with_info(opj_dinfo_t *dinfo, opj_cio_t *cio, opj_codestream_info_t *cstr_info) { - if(dinfo && cio) { - switch(dinfo->codec_format) { - case CODEC_J2K: - return j2k_decode((opj_j2k_t*)dinfo->j2k_handle, cio, cstr_info); - case CODEC_JPT: - return j2k_decode_jpt_stream((opj_j2k_t*)dinfo->j2k_handle, cio, cstr_info); - case CODEC_JP2: - return jp2_decode((opj_jp2_t*)dinfo->jp2_handle, cio, cstr_info); - case CODEC_UNKNOWN: - default: - break; +/** + * Writes a tile with the given data. + * + * @param p_compressor the jpeg2000 codec. + * @param p_tile_index the index of the tile to write. At the moment, the tiles must be written from 0 to n-1 in sequence. + * @param p_data pointer to the data to write. Data is arranged in sequence, data_comp0, then data_comp1, then ... NO INTERLEAVING should be set. + * @param p_data_size this value os used to make sure the data being written is correct. The size must be equal to the sum for each component of tile_width * tile_height * component_size. component_size can be 1,2 or 4 bytes, + * depending on the precision of the given component. + * @param p_stream the stream to write data to. + */ +bool opj_write_tile ( + opj_codec_t *p_codec, + OPJ_UINT32 p_tile_index, + OPJ_BYTE * p_data, + OPJ_UINT32 p_data_size, + opj_stream_t *p_stream + ) +{ + if + (p_codec && p_stream && p_data) + { + opj_codec_private_t * l_info = (opj_codec_private_t *) p_codec; + opj_stream_private_t * l_cio = (opj_stream_private_t *) p_stream; + if + (l_info->is_decompressor) + { + return false; + } + return l_info->m_codec_data.m_compression.opj_write_tile(l_info->m_codec,p_tile_index,p_data,p_data_size,l_cio,&(l_info->m_event_mgr)); + } + return false; +} + +/** + * Reads a tile header. This function is compulsory and allows one to know the size of the tile thta will be decoded. + * The user may need to refer to the image got by opj_read_header to understand the size being taken by the tile. + * + * @param p_codec the jpeg2000 codec. + * @param p_tile_index pointer to a value that will hold the index of the tile being decoded, in case of success. + * @param p_data_size pointer to a value that will hold the maximum size of the decoded data, in case of success. In case + * of truncated codestreams, the actual number of bytes decoded may be lower. The computation of the size is the same + * as depicted in opj_write_tile. + * @param p_tile_x0 pointer to a value that will hold the x0 pos of the tile (in the image). + * @param p_tile_y0 pointer to a value that will hold the y0 pos of the tile (in the image). + * @param p_tile_x1 pointer to a value that will hold the x1 pos of the tile (in the image). + * @param p_tile_y1 pointer to a value that will hold the y1 pos of the tile (in the image). + * @param p_nb_comps pointer to a value that will hold the number of components in the tile. + * @param p_should_go_on pointer to a boolean that will hold the fact that the decoding should go on. In case the + * codestream is over at the time of the call, the value will be set to false. The user should then stop + * the decoding. + * @param p_stream the stream to decode. + * @return true if the tile header could be decoded. In case the decoding should end, the returned value is still true. + * returning false may be the result of a shortage of memory or an internal error. + */ +bool opj_read_tile_header( + opj_codec_t *p_codec, + 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, + bool * p_should_go_on, + opj_stream_t * p_stream) +{ + if + (p_codec && p_stream && p_data_size && p_tile_index) + { + opj_codec_private_t * l_info = (opj_codec_private_t *) p_codec; + opj_stream_private_t * l_cio = (opj_stream_private_t *) p_stream; + if + (! l_info->is_decompressor) + { + return false; + } + return l_info->m_codec_data.m_decompression.opj_read_tile_header( + l_info->m_codec, + p_tile_index, + p_data_size, + p_tile_x0, + p_tile_y0, + p_tile_x1, + p_tile_y1, + p_nb_comps, + p_should_go_on, + l_cio,&(l_info->m_event_mgr)); + } + return false; +} + +/** + * Reads a tile data. This function is compulsory and allows one to decode tile data. opj_read_tile_header should be called before. + * The user may need to refer to the image got by opj_read_header to understand the size being taken by the tile. + * + * @param p_codec the jpeg2000 codec. + * @param p_tile_index the index of the tile being decoded, this should be the value set by opj_read_tile_header. + * @param p_data pointer to a memory block that will hold the decoded data. + * @param p_data_size size of p_data. p_data_size should be bigger or equal to the value set by opj_read_tile_header. + * @param p_stream the stream to decode. + * + * @return true if the data could be decoded. + */ +bool opj_decode_tile_data( + opj_codec_t *p_codec, + OPJ_UINT32 p_tile_index, + OPJ_BYTE * p_data, + OPJ_UINT32 p_data_size, + opj_stream_t *p_stream + ) +{ + if + (p_codec && p_data && p_stream) + { + opj_codec_private_t * l_info = (opj_codec_private_t *) p_codec; + opj_stream_private_t * l_cio = (opj_stream_private_t *) p_stream; + if + (! l_info->is_decompressor) + { + return false; } + return l_info->m_codec_data.m_decompression.opj_decode_tile_data(l_info->m_codec,p_tile_index,p_data,p_data_size,l_cio,&(l_info->m_event_mgr)); } - return NULL; + return false; } -opj_cinfo_t* OPJ_CALLCONV opj_create_compress(OPJ_CODEC_FORMAT format) { - opj_cinfo_t *cinfo = (opj_cinfo_t*)opj_calloc(1, sizeof(opj_cinfo_t)); - if(!cinfo) return NULL; - cinfo->is_decompressor = false; - switch(format) { +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 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)); + } + return false; +} + +/** + * 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_codec 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). + * + * @return true if the area could be set. + */ +bool opj_set_decode_area( + opj_codec_t *p_codec, + OPJ_INT32 p_start_x, + OPJ_INT32 p_start_y, + OPJ_INT32 p_end_x, + OPJ_INT32 p_end_y + ) +{ + if + (p_codec) + { + opj_codec_private_t * l_info = (opj_codec_private_t *) p_codec; + if + (! l_info->is_decompressor) + { + return false; + } + return l_info->m_codec_data.m_decompression.opj_set_decode_area( + l_info->m_codec, + p_start_x, + p_start_y, + p_end_x, + p_end_y, + &(l_info->m_event_mgr)); + + } + return false; + +} + +bool OPJ_CALLCONV opj_end_decompress (opj_codec_t *p_codec,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 false; + } + return l_info->m_codec_data.m_decompression.opj_end_decompress(l_info->m_codec,l_cio,&(l_info->m_event_mgr)); + } + return false; +} + + +opj_codec_t* OPJ_CALLCONV opj_create_compress(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 = 0; + switch + (p_format) + { case CODEC_J2K: - /* get a J2K coder handle */ - cinfo->j2k_handle = (void*)j2k_create_compress((opj_common_ptr)cinfo); - if(!cinfo->j2k_handle) { - opj_free(cinfo); - return NULL; + l_info->m_codec_data.m_compression.opj_encode = (bool (*) (void *, struct opj_stream_private *, struct opj_event_mgr * )) j2k_encode; + l_info->m_codec_data.m_compression.opj_end_compress = (bool (*) (void *, struct opj_stream_private *, struct opj_event_mgr *)) j2k_end_compress; + l_info->m_codec_data.m_compression.opj_start_compress = (bool (*) (void *,struct opj_stream_private *,struct opj_image * , struct opj_event_mgr *)) j2k_start_compress; + l_info->m_codec_data.m_compression.opj_write_tile = (bool (*) (void *,OPJ_UINT32,OPJ_BYTE*,OPJ_UINT32,struct opj_stream_private *, struct opj_event_mgr *)) j2k_write_tile; + l_info->m_codec_data.m_compression.opj_destroy = (void (*) (void *)) j2k_destroy; + l_info->m_codec_data.m_compression.opj_setup_encoder = (void (*) (void *,opj_cparameters_t *,struct opj_image *, struct opj_event_mgr * )) j2k_setup_encoder; + + l_info->m_codec = j2k_create_compress(); + if + (! l_info->m_codec) + { + opj_free(l_info); + return 00; } break; + case CODEC_JP2: - /* get a JP2 coder handle */ - cinfo->jp2_handle = (void*)jp2_create_compress((opj_common_ptr)cinfo); - if(!cinfo->jp2_handle) { - opj_free(cinfo); - return NULL; + /* get a JP2 decoder handle */ + l_info->m_codec_data.m_compression.opj_encode = (bool (*) (void *, struct opj_stream_private *, struct opj_event_mgr * )) jp2_encode; + l_info->m_codec_data.m_compression.opj_end_compress = (bool (*) (void *, struct opj_stream_private *, struct opj_event_mgr *)) jp2_end_compress; + l_info->m_codec_data.m_compression.opj_start_compress = (bool (*) (void *,struct opj_stream_private *,struct opj_image * , struct opj_event_mgr *)) jp2_start_compress; + l_info->m_codec_data.m_compression.opj_write_tile = (bool (*) (void *,OPJ_UINT32,OPJ_BYTE*,OPJ_UINT32,struct opj_stream_private *, struct opj_event_mgr *)) jp2_write_tile; + l_info->m_codec_data.m_compression.opj_destroy = (void (*) (void *)) jp2_destroy; + l_info->m_codec_data.m_compression.opj_setup_encoder = (void (*) (void *,opj_cparameters_t *,struct opj_image *, struct opj_event_mgr * )) jp2_setup_encoder; + + l_info->m_codec = jp2_create(false); + if + (! l_info->m_codec) + { + opj_free(l_info); + return 00; } break; - case CODEC_JPT: case CODEC_UNKNOWN: + case CODEC_JPT: default: - opj_free(cinfo); - return NULL; - } - - cinfo->codec_format = format; - - return cinfo; -} - -void OPJ_CALLCONV opj_destroy_compress(opj_cinfo_t *cinfo) { - if(cinfo) { - /* destroy the codec */ - switch(cinfo->codec_format) { - case CODEC_J2K: - j2k_destroy_compress((opj_j2k_t*)cinfo->j2k_handle); - break; - case CODEC_JP2: - jp2_destroy_compress((opj_jp2_t*)cinfo->jp2_handle); - break; - case CODEC_JPT: - case CODEC_UNKNOWN: - default: - break; - } - /* destroy the decompressor */ - opj_free(cinfo); + opj_free(l_info); + return 00; } + set_default_event_handler(&(l_info->m_event_mgr)); + return (opj_codec_t*) l_info; } void OPJ_CALLCONV opj_set_default_encoder_parameters(opj_cparameters_t *parameters) { @@ -238,10 +654,6 @@ void OPJ_CALLCONV opj_set_default_encoder_parameters(opj_cparameters_t *paramete parameters->tp_on = 0; parameters->decod_format = -1; parameters->cod_format = -1; - parameters->tcp_rates[0] = 0; - parameters->tcp_numlayers = 1; - parameters->cp_disto_alloc = 1; - /* UniPG>> */ #ifdef USE_JPWL parameters->jpwl_epc_on = false; @@ -277,38 +689,153 @@ void OPJ_CALLCONV opj_set_default_encoder_parameters(opj_cparameters_t *paramete } } -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) { - case CODEC_J2K: - j2k_setup_encoder((opj_j2k_t*)cinfo->j2k_handle, parameters, image); - break; - case CODEC_JP2: - jp2_setup_encoder((opj_jp2_t*)cinfo->jp2_handle, parameters, image); - break; - case CODEC_JPT: - case CODEC_UNKNOWN: - default: - break; +/** + * 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,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,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; +} + + +bool OPJ_CALLCONV opj_setup_encoder(opj_codec_t *p_info, opj_cparameters_t *parameters, opj_image_t *image) +{ + if + (p_info && parameters && image) + { + opj_codec_private_t * l_codec = ((opj_codec_private_t *) p_info); + if + (! l_codec->is_decompressor) + { + l_codec->m_codec_data.m_compression.opj_setup_encoder(l_codec->m_codec,parameters,image,&(l_codec->m_event_mgr)); + return true; + } + } + return false; +} + +bool OPJ_CALLCONV opj_encode(opj_codec_t *p_info, opj_stream_t *cio) +{ + if + (p_info && cio) + { + opj_codec_private_t * l_codec = (opj_codec_private_t *) p_info; + opj_stream_private_t * l_cio = (opj_stream_private_t *) cio; + if + (! l_codec->is_decompressor) + { + l_codec->m_codec_data.m_compression.opj_encode(l_codec->m_codec,l_cio,&(l_codec->m_event_mgr)); + return true; + } + } + return false; + +} + +bool OPJ_CALLCONV opj_start_compress (opj_codec_t *p_codec,opj_image_t * p_image,opj_stream_t *p_cio) +{ + if + (p_codec && p_cio) + { + opj_codec_private_t * l_codec = (opj_codec_private_t *) p_codec; + opj_stream_private_t * l_cio = (opj_stream_private_t *) p_cio; + if + (! l_codec->is_decompressor) + { + return l_codec->m_codec_data.m_compression.opj_start_compress(l_codec->m_codec,l_cio,p_image,&(l_codec->m_event_mgr)); } } + return false; +} + +bool OPJ_CALLCONV opj_end_compress (opj_codec_t *p_codec,opj_stream_t *p_cio) +{ + if + (p_codec && p_cio) + { + opj_codec_private_t * l_codec = (opj_codec_private_t *) p_codec; + opj_stream_private_t * l_cio = (opj_stream_private_t *) p_cio; + if + (! l_codec->is_decompressor) + { + return l_codec->m_codec_data.m_compression.opj_end_compress(l_codec->m_codec,l_cio,&(l_codec->m_event_mgr)); + } + } + return false; + +} + +bool OPJ_CALLCONV opj_set_info_handler(opj_codec_t * p_codec, opj_msg_callback p_callback,void * p_user_data) +{ + opj_codec_private_t * l_codec = (opj_codec_private_t *) p_codec; + if + (! l_codec) + { + return false; + } + l_codec->m_event_mgr.info_handler = p_callback; + l_codec->m_event_mgr.m_info_data = p_user_data; + return true; } -bool OPJ_CALLCONV opj_encode(opj_cinfo_t *cinfo, opj_cio_t *cio, opj_image_t *image, char *index) { - if (index != NULL) - opj_event_msg((opj_common_ptr)cinfo, EVT_WARNING, "Set index to NULL when calling the opj_encode function.\n" - "To extract the index, use the opj_encode_with_info() function.\n" - "No index will be generated during this encoding\n"); - return opj_encode_with_info(cinfo, cio, image, NULL); +bool OPJ_CALLCONV opj_set_warning_handler(opj_codec_t * p_codec, opj_msg_callback p_callback,void * p_user_data) +{ + opj_codec_private_t * l_codec = (opj_codec_private_t *) p_codec; + if + (! l_codec) + { + return false; + } + l_codec->m_event_mgr.warning_handler = p_callback; + l_codec->m_event_mgr.m_warning_data = p_user_data; + return true; +} + +bool OPJ_CALLCONV opj_set_error_handler(opj_codec_t * p_codec, opj_msg_callback p_callback,void * p_user_data) +{ + opj_codec_private_t * l_codec = (opj_codec_private_t *) p_codec; + if + (! l_codec) + { + return false; + } + l_codec->m_event_mgr.error_handler = p_callback; + l_codec->m_event_mgr.m_error_data = p_user_data; + return true; } -bool OPJ_CALLCONV opj_encode_with_info(opj_cinfo_t *cinfo, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info) { +/*bool OPJ_CALLCONV opj_encode_with_info(opj_cinfo_t *cinfo, opj_stream_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info) { if(cinfo && cio && image) { switch(cinfo->codec_format) { case CODEC_J2K: - return j2k_encode((opj_j2k_t*)cinfo->j2k_handle, cio, image, cstr_info); + return j2k_encode((opj_j2k_t*)cinfo->j2k_handle, (opj_stream_private_t *) cio, image, cstr_info); case CODEC_JP2: - return jp2_encode((opj_jp2_t*)cinfo->jp2_handle, cio, image, cstr_info); + return jp2_encode((opj_jp2_t*)cinfo->jp2_handle, (opj_stream_private_t *) cio, image, cstr_info); case CODEC_JPT: case CODEC_UNKNOWN: default: @@ -316,10 +843,12 @@ bool OPJ_CALLCONV opj_encode_with_info(opj_cinfo_t *cinfo, opj_cio_t *cio, opj_i } } return false; -} +}*/ void OPJ_CALLCONV opj_destroy_cstr_info(opj_codestream_info_t *cstr_info) { - if (cstr_info) { + if + (cstr_info) + { int tileno; for (tileno = 0; tileno < cstr_info->tw * cstr_info->th; tileno++) { opj_tile_info_t *tile_info = &cstr_info->tile[tileno]; @@ -329,6 +858,45 @@ void OPJ_CALLCONV opj_destroy_cstr_info(opj_codestream_info_t *cstr_info) { } opj_free(cstr_info->tile); opj_free(cstr_info->marker); - opj_free(cstr_info->numdecompos); } } + +bool opj_set_MCT(opj_cparameters_t *parameters,OPJ_FLOAT32 * pEncodingMatrix,OPJ_INT32 * p_dc_shift,OPJ_UINT32 pNbComp) +{ + OPJ_UINT32 l_matrix_size = pNbComp * pNbComp * sizeof(OPJ_FLOAT32); + OPJ_UINT32 l_dc_shift_size = pNbComp * sizeof(OPJ_INT32); + OPJ_UINT32 l_mct_total_size = l_matrix_size + l_dc_shift_size; + // add MCT capability + parameters->cp_rsiz |= 0x8100; + parameters->irreversible = 1; + // use array based MCT + parameters->tcp_mct = 2; + parameters->mct_data = opj_malloc(l_mct_total_size); + if + (! parameters->mct_data) + { + return false; + } + memcpy(parameters->mct_data,pEncodingMatrix,l_matrix_size); + memcpy(((OPJ_BYTE *) parameters->mct_data) + l_matrix_size,p_dc_shift,l_dc_shift_size); + return true; +} + +/** + * Restricts the decoding to the given image area. + * + * @param parameters the parameters to update. + * @param p_start_x the starting x position of the area to decode. + * @param p_start_y the starting y position of the area to decode. + * @param p_end_x the x end position of the area to decode. + * @param p_end_x the y end position of the area to decode. + */ +OPJ_API bool OPJ_CALLCONV opj_restrict_decoding (opj_dparameters_t *parameters,OPJ_INT32 p_start_x,OPJ_INT32 p_start_y,OPJ_INT32 p_end_x,OPJ_INT32 p_end_y) +{ + parameters->m_use_restrict_decode = 1; + parameters->m_decode_start_x = p_start_x; + parameters->m_decode_start_y = p_start_y; + parameters->m_decode_end_x = p_end_x; + parameters->m_decode_end_y = p_end_y; + return true; +} diff --git a/libopenjpeg/openjpeg.h b/libopenjpeg/openjpeg.h index ffcaacaf..48d863e1 100644 --- a/libopenjpeg/openjpeg.h +++ b/libopenjpeg/openjpeg.h @@ -6,6 +6,7 @@ * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe * Copyright (c) 2005, Herve Drolon, FreeImage Team * Copyright (c) 2006-2007, Parvatha Elangovan + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,58 +33,59 @@ #ifndef OPENJPEG_H #define OPENJPEG_H -#define OPENJPEG_VERSION "1.3.0" +#if defined(OPJ_STATIC) || !(defined(WIN32) || defined(__WIN32__)) + #define OPJ_API + #define OPJ_CALLCONV +#else + #define OPJ_CALLCONV __stdcall + #ifdef OPJ_EXPORTS + #define OPJ_API __declspec(dllexport) + #else + #define OPJ_API __declspec(dllimport) + #endif /* OPJ_EXPORTS */ +#endif /* !OPJ_STATIC || !WIN32 */ +#ifndef __cplusplus + #if defined(HAVE_STDBOOL_H) + #include <stdbool.h> + #else + #if !defined(bool) + #define bool int + #endif + #if !defined(true) + #define true 1 + #endif + #if !defined(false) + #define false 0 + #endif + #endif +#endif /* __cplusplus */ +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; +#if defined(_MSC_VER) || defined(__BORLANDC__) + typedef __int64 OPJ_INT64; +#else + typedef long long OPJ_INT64; +#endif + +#define OPENJPEG_VERSION "1.2.0" /* ========================================================== Compiler directives ========================================================== */ +#include <stdio.h> + + -#if defined(OPJ_STATIC) || !(defined(WIN32) || defined(__WIN32__)) -#define OPJ_API -#define OPJ_CALLCONV -#else -#define OPJ_CALLCONV __stdcall -/* -The following ifdef block is the standard way of creating macros which make exporting -from a DLL simpler. All files within this DLL are compiled with the OPJ_EXPORTS -symbol defined on the command line. this symbol should not be defined on any project -that uses this DLL. This way any other project whose source files include this file see -OPJ_API functions as being imported from a DLL, wheras this DLL sees symbols -defined with this macro as being exported. -*/ -#ifdef OPJ_EXPORTS -#define OPJ_API __declspec(dllexport) -#else -#define OPJ_API __declspec(dllimport) -#endif /* OPJ_EXPORTS */ -#endif /* !OPJ_STATIC || !WIN32 */ -#ifndef __cplusplus -#if defined(HAVE_STDBOOL_H) -/* -The C language implementation does correctly provide the standard header -file "stdbool.h". - */ -#include <stdbool.h> -#else -/* -The C language implementation does not provide the standard header file -"stdbool.h" as required by ISO/IEC 9899:1999. Try to compensate for this -braindamage below. -*/ -#if !defined(bool) -#define bool int -#endif -#if !defined(true) -#define true 1 -#endif -#if !defined(false) -#define false 0 -#endif -#endif -#endif /* __cplusplus */ /* ========================================================== @@ -91,10 +93,14 @@ braindamage below. ========================================================== */ -#define OPJ_PATH_LEN 4096 /**< Maximum allowed size for filenames */ - -#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 OPJ_PATH_LEN 4096 /**< Maximum allowed size for filenames */ +#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 */ @@ -118,7 +124,8 @@ Rsiz Capabilities typedef enum RSIZ_CAPABILITIES { STD_RSIZ = 0, /** Standard JPEG2000 profile*/ CINEMA2K = 3, /** Profile name for a 2K image*/ - CINEMA4K = 4 /** Profile name for a 4K image*/ + CINEMA4K = 4, /** Profile name for a 4K image*/ + MCT = 0x8100 } OPJ_RSIZ_CAPABILITIES; /** @@ -163,14 +170,8 @@ typedef enum CODEC_FORMAT { CODEC_JP2 = 2 /**< JPEG-2000 file format : read/write */ } OPJ_CODEC_FORMAT; -/** -Limit decoding to certain portions of the codestream. -*/ -typedef enum LIMIT_DECODING { - NO_LIMITATION = 0, /**< No limitation for the decoding. The entire codestream will de decoded */ - LIMIT_TO_MAIN_HEADER = 1, /**< The decoding is limited to the Main Header */ - DECODE_ALL_BUT_PACKETS = 2 /**< Decode everything except the JPEG 2000 packets */ -} OPJ_LIMIT_DECODING; + + /* ========================================================== @@ -183,25 +184,9 @@ Callback function prototype for events @param msg Event message @param client_data */ -typedef void (*opj_msg_callback) (const char *msg, void *client_data); +typedef void (*opj_msg_callback) (const OPJ_CHAR *msg, void *client_data); + -/** -Message handler object -used for -<ul> -<li>Error messages -<li>Warning messages -<li>Debugging messages -</ul> -*/ -typedef struct opj_event_mgr { - /** Error message callback if available, NULL otherwise */ - opj_msg_callback error_handler; - /** Warning message callback if available, NULL otherwise */ - opj_msg_callback warning_handler; - /** Debug message callback if available, NULL otherwise */ - opj_msg_callback info_handler; -} opj_event_mgr_t; /* @@ -213,29 +198,30 @@ typedef struct opj_event_mgr { /** Progression order changes */ -typedef struct opj_poc { +typedef struct opj_poc +{ /** Resolution num start, Component num start, given by POC */ - int resno0, compno0; + OPJ_UINT32 resno0, compno0; /** Layer num end,Resolution num end, Component num end, given by POC */ - int layno1, resno1, compno1; + OPJ_UINT32 layno1, resno1, compno1; /** Layer num start,Precinct num start, Precinct num end */ - int layno0, precno0, precno1; + OPJ_UINT32 layno0, precno0, precno1; /** Progression order enum*/ OPJ_PROG_ORDER prg1,prg; /** Progression order string*/ - char progorder[5]; + OPJ_CHAR progorder[5]; /** Tile number */ - int tile; + OPJ_UINT32 tile; /** Start and end values for Tile width and height*/ - int tx0,tx1,ty0,ty1; + OPJ_INT32 tx0,tx1,ty0,ty1; /** Start value, initialised in pi_initialise_encode*/ - int layS, resS, compS, prcS; + OPJ_UINT32 layS, resS, compS, prcS; /** End value, initialised in pi_initialise_encode */ - int layE, resE, compE, prcE; + OPJ_UINT32 layE, resE, compE, prcE; /** Start and end values of Tile width and height, initialised in pi_initialise_encode*/ - int txS,txE,tyS,tyE,dx,dy; + OPJ_UINT32 txS,txE,tyS,tyE,dx,dy; /** Temporary values for Tile parts, initialised in pi_create_encode */ - int lay_t, res_t, comp_t, prc_t,tx0_t,ty0_t; + OPJ_UINT32 lay_t, res_t, comp_t, prc_t,tx0_t,ty0_t; } opj_poc_t; /** @@ -365,6 +351,9 @@ typedef struct opj_cparameters { char tp_flag; /** MCT (multiple component transform) */ char tcp_mct; + /** Naive implementation of MCT restricted to a single reversible array based encoding without offset concerning all the components. */ + void * mct_data; + } opj_cparameters_t; /** @@ -387,6 +376,14 @@ typedef struct opj_dparameters { */ int cp_layer; + /** + * Restrictive decoding parameters. + */ + OPJ_INT32 m_decode_start_x; + OPJ_INT32 m_decode_start_y ; + OPJ_INT32 m_decode_end_x ; + OPJ_INT32 m_decode_end_y ; + /**@name command line encoder parameters (not used inside the library) */ /*@{*/ /** input file name */ @@ -408,61 +405,19 @@ typedef struct opj_dparameters { int jpwl_exp_comps; /** maximum number of tiles */ int jpwl_max_tiles; + + /** use restrictive decoding ? */ + OPJ_UINT32 m_use_restrict_decode : 1; /*@}*/ /* <<UniPG */ - /** - Specify whether the decoding should be done on the entire codestream, or be limited to the main header - Limiting the decoding to the main header makes it possible to extract the characteristics of the codestream - if == NO_LIMITATION, the entire codestream is decoded; - if == LIMIT_TO_MAIN_HEADER, only the main header is decoded; - */ - OPJ_LIMIT_DECODING cp_limit_decoding; - } opj_dparameters_t; -/** Common fields between JPEG-2000 compression and decompression master structs. */ - -#define opj_common_fields \ - opj_event_mgr_t *event_mgr; /**< pointer to the event manager */\ - void * client_data; /**< Available for use by application */\ - bool is_decompressor; /**< So common code can tell which is which */\ - OPJ_CODEC_FORMAT codec_format; /**< selected codec */\ - void *j2k_handle; /**< pointer to the J2K codec */\ - void *jp2_handle; /**< pointer to the JP2 codec */\ - void *mj2_handle /**< pointer to the MJ2 codec */ - -/* Routines that are to be used by both halves of the library are declared - * to receive a pointer to this structure. There are no actual instances of - * opj_common_struct_t, only of opj_cinfo_t and opj_dinfo_t. - */ -typedef struct opj_common_struct { - opj_common_fields; /* Fields common to both master struct types */ - /* Additional fields follow in an actual opj_cinfo_t or - * opj_dinfo_t. All three structs must agree on these - * initial fields! (This would be a lot cleaner in C++.) - */ -} opj_common_struct_t; - -typedef opj_common_struct_t * opj_common_ptr; - /** -Compression context info -*/ -typedef struct opj_cinfo { - /** Fields shared with opj_dinfo_t */ - opj_common_fields; - /* other specific fields go here */ -} opj_cinfo_t; + * J2k codec. + */ +typedef void * opj_codec_t; -/** -Decompression context info -*/ -typedef struct opj_dinfo { - /** Fields shared with opj_cinfo_t */ - opj_common_fields; - /* other specific fields go here */ -} opj_dinfo_t; /* ========================================================== @@ -478,27 +433,14 @@ typedef struct opj_dinfo { /** The stream was opened for writing. */ #define OPJ_STREAM_WRITE 0x0002 -/** -Byte input-output stream (CIO) -*/ -typedef struct opj_cio { - /** codec context */ - opj_common_ptr cinfo; - /** open mode (read/write) either OPJ_STREAM_READ or OPJ_STREAM_WRITE */ - int openmode; - /** pointer to the start of the buffer */ - unsigned char *buffer; - /** buffer size in bytes */ - int length; +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 bool (* opj_stream_seek_fn) (OPJ_SIZE_T p_nb_bytes, void * p_user_data) ; + - /** pointer to the start of the stream */ - unsigned char *start; - /** pointer to the end of the stream */ - unsigned char *end; - /** pointer to the current position */ - unsigned char *bp; -} opj_cio_t; +typedef void * opj_stream_t; /* ========================================================== @@ -511,45 +453,45 @@ Defines a single image component */ typedef struct opj_image_comp { /** XRsiz: horizontal separation of a sample of ith component with respect to the reference grid */ - int dx; + OPJ_UINT32 dx; /** YRsiz: vertical separation of a sample of ith component with respect to the reference grid */ - int dy; + OPJ_UINT32 dy; /** data width */ - int w; + OPJ_UINT32 w; /** data height */ - int h; + OPJ_UINT32 h; /** x component offset compared to the whole image */ - int x0; + OPJ_INT32 x0; /** y component offset compared to the whole image */ - int y0; + OPJ_INT32 y0; /** precision */ - int prec; - /** image depth in bits */ - int bpp; - /** signed (1) / unsigned (0) */ - int sgnd; + OPJ_UINT32 prec; /** number of decoded resolution */ - int resno_decoded; + OPJ_UINT32 resno_decoded; /** number of division by 2 of the out image compared to the original size of image */ - int factor; + OPJ_UINT32 factor; /** image component data */ int *data; + /** signed (1) / unsigned (0) */ + OPJ_UINT32 sgnd : 1; + } opj_image_comp_t; /** Defines image data and characteristics */ -typedef struct opj_image { +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_INT32 x0; /** YOsiz: vertical offset from the origin of the reference grid to the top side of the image area */ - int y0; + OPJ_INT32 y0; /** Xsiz: width of the reference grid */ - int x1; + OPJ_INT32 x1; /** Ysiz: height of the reference grid */ - int y1; + OPJ_INT32 y1; /** number of components in the image */ - int numcomps; + OPJ_UINT32 numcomps; /** color space: sRGB, Greyscale or YUV */ OPJ_COLOR_SPACE color_space; /** image components */ @@ -561,13 +503,13 @@ Component parameters structure used by the opj_image_create function */ typedef struct opj_image_comptparm { /** XRsiz: horizontal separation of a sample of ith component with respect to the reference grid */ - int dx; + unsigned int dx; /** YRsiz: vertical separation of a sample of ith component with respect to the reference grid */ - int dy; + unsigned int dy; /** data width */ - int w; + unsigned int w; /** data height */ - int h; + unsigned int h; /** x component offset compared to the whole image */ int x0; /** y component offset compared to the whole image */ @@ -727,7 +669,7 @@ extern "C" { ========================================================== */ -OPJ_API const char * OPJ_CALLCONV opj_version(void); +OPJ_API const OPJ_CHAR * OPJ_CALLCONV opj_version(void); /* ========================================================== @@ -742,7 +684,18 @@ Create an image @param clrspc image color space @return returns a new image structure if successful, returns NULL otherwise */ -OPJ_API opj_image_t* OPJ_CALLCONV opj_image_create(int numcmpts, opj_image_cmptparm_t *cmptparms, OPJ_COLOR_SPACE clrspc); +OPJ_API opj_image_t* OPJ_CALLCONV opj_image_create(OPJ_UINT32 numcmpts, opj_image_cmptparm_t *cmptparms, OPJ_COLOR_SPACE clrspc); + +/** + * Creates an image without allocating memory for the image (used in the new version of the library). + * + * @param p_num_cmpts the number of components + * @param p_cmpt_parms the components parameters + * @param p_clr_spc the image color space + * + * @return a new image structure if successful, NULL otherwise. +*/ +OPJ_API opj_image_t* OPJ_CALLCONV opj_image_tile_create(OPJ_UINT32 numcmpts, opj_image_cmptparm_t *cmptparms, OPJ_COLOR_SPACE clrspc); /** Deallocate any resources associated with an image @@ -757,44 +710,80 @@ OPJ_API void OPJ_CALLCONV opj_image_destroy(opj_image_t *image); */ /** -Open and allocate a memory stream for read / write. -On reading, the user must provide a buffer containing encoded data. The buffer will be -wrapped by the returned CIO handle. -On writing, buffer parameters must be set to 0: a buffer will be allocated by the library -to contain encoded data. -@param cinfo Codec context info -@param buffer Reading: buffer address. Writing: NULL -@param length Reading: buffer length. Writing: 0 -@return Returns a CIO handle if successful, returns NULL otherwise + * 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_cio_t* OPJ_CALLCONV opj_cio_open(opj_common_ptr cinfo, unsigned char *buffer, int length); +OPJ_API opj_stream_t* OPJ_CALLCONV opj_stream_default_create(bool p_is_input); +OPJ_API opj_stream_t* OPJ_CALLCONV opj_stream_create(OPJ_UINT32 p_size,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); /** -Close and free a CIO handle -@param cio CIO handle to free + * 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_cio_close(opj_cio_t *cio); +OPJ_API void OPJ_CALLCONV opj_stream_set_read_function(opj_stream_t* p_stream, opj_stream_read_fn p_function); /** -Get position in byte stream -@param cio CIO handle -@return Returns the position in bytes + * 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 int OPJ_CALLCONV cio_tell(opj_cio_t *cio); +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); + /** -Set position in byte stream -@param cio CIO handle -@param pos Position, in number of bytes, from the beginning of the stream + * 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 cio_seek(opj_cio_t *cio, int pos); +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,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, bool p_is_read_stream); + + /* ========================================================== event manager functions definitions ========================================================== */ +OPJ_API bool OPJ_CALLCONV opj_set_info_handler(opj_codec_t * p_codec, opj_msg_callback p_callback,void * p_user_data); +OPJ_API bool OPJ_CALLCONV opj_set_warning_handler(opj_codec_t * p_codec, opj_msg_callback p_callback,void * p_user_data); +OPJ_API bool OPJ_CALLCONV opj_set_error_handler(opj_codec_t * p_codec, opj_msg_callback p_callback,void * p_user_data); + -OPJ_API opj_event_mgr_t* OPJ_CALLCONV opj_set_event_mgr(opj_common_ptr cinfo, opj_event_mgr_t *event_mgr, void *context); /* ========================================================== @@ -806,31 +795,130 @@ 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_dinfo_t* OPJ_CALLCONV opj_create_decompress(OPJ_CODEC_FORMAT format); -/** -Destroy a decompressor handle -@param dinfo decompressor handle to destroy -*/ -OPJ_API void OPJ_CALLCONV opj_destroy_decompress(opj_dinfo_t *dinfo); +OPJ_API opj_codec_t* OPJ_CALLCONV opj_create_decompress(OPJ_CODEC_FORMAT format); + /** Set decoding parameters to default values @param parameters Decompression parameters */ OPJ_API void OPJ_CALLCONV opj_set_default_decoder_parameters(opj_dparameters_t *parameters); + +#ifdef USE_OPJ_DEPRECATED +#ifdef _MSC_VER +#pragma message ( "warning, opj_setup_decoder is deprecated") +#else +#warning "warning, opj_setup_decoder is deprecated" +#endif /** Setup the decoder decoding parameters using user parameters. Decoding parameters are returned in j2k->cp. @param dinfo decompressor handle @param parameters decompression parameters */ -OPJ_API void OPJ_CALLCONV opj_setup_decoder(opj_dinfo_t *dinfo, opj_dparameters_t *parameters); +OPJ_API bool OPJ_CALLCONV opj_setup_decoder(opj_codec_t *dinfo, opj_dparameters_t *parameters); +#endif + /** Decode an image from a JPEG-2000 codestream @param dinfo decompressor handle @param cio Input buffer stream @return Returns a decoded image if successful, returns NULL otherwise */ -OPJ_API opj_image_t* OPJ_CALLCONV opj_decode(opj_dinfo_t *dinfo, opj_cio_t *cio); +OPJ_API opj_image_t* OPJ_CALLCONV opj_decode(opj_codec_t *p_decompressor, opj_stream_t * cio); + +/** + * Writes a tile with the given data. + * + * @param p_compressor the jpeg2000 codec. + * @param p_tile_index the index of the tile to write. At the moment, the tiles must be written from 0 to n-1 in sequence. + * @param p_data pointer to the data to write. Data is arranged in sequence, data_comp0, then data_comp1, then ... NO INTERLEAVING should be set. + * @param p_data_size this value os used to make sure the data being written is correct. The size must be equal to the sum for each component of tile_width * tile_height * component_size. component_size can be 1,2 or 4 bytes, + * depending on the precision of the given component. + * @param p_stream the stream to write data to. + * + * @return true if the data could be written. + */ +OPJ_API bool OPJ_CALLCONV opj_write_tile ( + opj_codec_t *p_codec, + OPJ_UINT32 p_tile_index, + OPJ_BYTE * p_data, + OPJ_UINT32 p_data_size, + opj_stream_t *p_stream + ); + +/** + * Reads a tile header. This function is compulsory and allows one to know the size of the tile thta will be decoded. + * The user may need to refer to the image got by opj_read_header to understand the size being taken by the tile. + * + * @param p_codec the jpeg2000 codec. + * @param p_tile_index pointer to a value that will hold the index of the tile being decoded, in case of success. + * @param p_data_size pointer to a value that will hold the maximum size of the decoded data, in case of success. In case + * of truncated codestreams, the actual number of bytes decoded may be lower. The computation of the size is the same + * as depicted in opj_write_tile. + * @param p_tile_x0 pointer to a value that will hold the x0 pos of the tile (in the image). + * @param p_tile_y0 pointer to a value that will hold the y0 pos of the tile (in the image). + * @param p_tile_x1 pointer to a value that will hold the x1 pos of the tile (in the image). + * @param p_tile_y1 pointer to a value that will hold the y1 pos of the tile (in the image). + * @param p_nb_comps pointer to a value that will hold the number of components in the tile. + * @param p_should_go_on pointer to a boolean that will hold the fact that the decoding should go on. In case the + * codestream is over at the time of the call, the value will be set to false. The user should then stop + * the decoding. + * @param p_stream the stream to decode. + * @return true if the tile header could be decoded. In case the decoding should end, the returned value is still true. + * returning false may be the result of a shortage of memory or an internal error. + */ +OPJ_API bool OPJ_CALLCONV opj_read_tile_header( + opj_codec_t *p_codec, + 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, + bool * p_should_go_on, + opj_stream_t * p_stream); + + +/** + * Reads a tile data. This function is compulsory and allows one to decode tile data. opj_read_tile_header should be called before. + * The user may need to refer to the image got by opj_read_header to understand the size being taken by the tile. + * + * @param p_codec the jpeg2000 codec. + * @param p_tile_index the index of the tile being decoded, this should be the value set by opj_read_tile_header. + * @param p_data pointer to a memory block that will hold the decoded data. + * @param p_data_size size of p_data. p_data_size should be bigger or equal to the value set by opj_read_tile_header. + * @param p_stream the stream to decode. + * + * @return true if the data could be decoded. + */ +OPJ_API bool OPJ_CALLCONV opj_decode_tile_data( + opj_codec_t *p_codec, + OPJ_UINT32 p_tile_index, + OPJ_BYTE * p_data, + OPJ_UINT32 p_data_size, + opj_stream_t *p_stream + ); + +/** + * 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_codec 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). + * + * @return true if the area could be set. + */ +OPJ_API bool OPJ_CALLCONV opj_set_decode_area( + opj_codec_t *p_codec, + OPJ_INT32 p_start_x, + OPJ_INT32 p_start_y, + OPJ_INT32 p_end_x, + OPJ_INT32 p_end_y + ); + /** Decode an image from a JPEG-2000 codestream and extract the codestream information @@ -839,18 +927,20 @@ Decode an image from a JPEG-2000 codestream and extract the codestream informati @param cstr_info Codestream information structure if needed afterwards, NULL otherwise @return Returns a decoded image if successful, returns NULL otherwise */ -OPJ_API opj_image_t* OPJ_CALLCONV opj_decode_with_info(opj_dinfo_t *dinfo, opj_cio_t *cio, opj_codestream_info_t *cstr_info); +//OPJ_API opj_image_t* OPJ_CALLCONV opj_decode_with_info(opj_dinfo_t *dinfo, opj_stream_t cio, opj_codestream_info_t *cstr_info); /** Creates a J2K/JP2 compression structure @param format Coder to select @return Returns a handle to a compressor if successful, returns NULL otherwise */ -OPJ_API opj_cinfo_t* OPJ_CALLCONV opj_create_compress(OPJ_CODEC_FORMAT format); +OPJ_API opj_codec_t* OPJ_CALLCONV opj_create_compress(OPJ_CODEC_FORMAT format); + /** -Destroy a compressor handle -@param cinfo compressor handle to destroy +Destroy a decompressor handle +@param dinfo decompressor handle to destroy */ -OPJ_API void OPJ_CALLCONV opj_destroy_compress(opj_cinfo_t *cinfo); +OPJ_API void OPJ_CALLCONV opj_destroy_codec(opj_codec_t * p_codec); + /** Set encoding parameters to default values, that means : <ul> @@ -873,13 +963,70 @@ Set encoding parameters to default values, that means : @param parameters Compression parameters */ OPJ_API void OPJ_CALLCONV opj_set_default_encoder_parameters(opj_cparameters_t *parameters); + +/** + * Sets the MCT matrix to use. + * + * @param parameters the parameters to change. + * @param pEncodingMatrix the encoding matrix. + * @param p_dc_shift the dc shift coefficients to use. + * @param pNbComp the number of components of the image. + * + * @return true if the parameters could be set. + */ +OPJ_API bool OPJ_CALLCONV opj_set_MCT(opj_cparameters_t *parameters,OPJ_FLOAT32 * pEncodingMatrix,OPJ_INT32 * p_dc_shift,OPJ_UINT32 pNbComp); + +/** + * Restricts the decoding to the given image area. + * + * @param parameters the parameters to update. + * @param p_start_x the starting x position of the area to decode. + * @param p_start_y the starting y position of the area to decode. + * @param p_end_x the x end position of the area to decode. + * @param p_end_x the y end position of the area to decode. + */ +OPJ_API bool OPJ_CALLCONV opj_restrict_decoding (opj_dparameters_t *parameters,OPJ_INT32 p_start_x,OPJ_INT32 p_start_y,OPJ_INT32 p_end_x,OPJ_INT32 p_end_y); + +#ifdef USE_OPJ_DEPRECATED +#ifdef _MSC_VER +#pragma message ("warning, opj_setup_encoder is deprecated") +#else +#warning "warning, opj_setup_encoder is deprecated" +#endif /** Setup the encoder parameters using the current image and using user parameters. @param cinfo Compressor handle @param parameters Compression parameters @param image Input filled image */ -OPJ_API void OPJ_CALLCONV opj_setup_encoder(opj_cinfo_t *cinfo, opj_cparameters_t *parameters, opj_image_t *image); +OPJ_API bool OPJ_CALLCONV opj_setup_encoder(opj_codec_t *cinfo, opj_cparameters_t *parameters, opj_image_t *image); +#endif + +/** + * 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 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); + + +OPJ_API bool OPJ_CALLCONV opj_end_decompress (opj_codec_t *p_codec,opj_stream_t *p_cio); /** Encode an image into a JPEG-2000 codestream @param cinfo compressor handle @@ -888,7 +1035,11 @@ Encode an image into a JPEG-2000 codestream @param index Depreacted -> Set to NULL. To extract index, used opj_encode_wci() @return Returns true if successful, returns false otherwise */ -OPJ_API bool OPJ_CALLCONV opj_encode(opj_cinfo_t *cinfo, opj_cio_t *cio, opj_image_t *image, char *index); +OPJ_API bool OPJ_CALLCONV opj_encode(opj_codec_t *cinfo, opj_stream_t * cio); + +OPJ_API bool OPJ_CALLCONV opj_start_compress (opj_codec_t *p_codec,opj_image_t * p_image,opj_stream_t *p_cio); + +OPJ_API bool OPJ_CALLCONV opj_end_compress (opj_codec_t *p_codec,opj_stream_t *p_cio); /** Encode an image into a JPEG-2000 codestream and extract the codestream information @param cinfo compressor handle @@ -897,15 +1048,32 @@ Encode an image into a JPEG-2000 codestream and extract the codestream informati @param cstr_info Codestream information structure if needed afterwards, NULL otherwise @return Returns true if successful, returns false otherwise */ -OPJ_API bool OPJ_CALLCONV opj_encode_with_info(opj_cinfo_t *cinfo, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info); +//OPJ_API bool OPJ_CALLCONV opj_encode_with_info(opj_cinfo_t *cinfo, opj_stream_t cio, opj_image_t *image, opj_codestream_info_t *cstr_info); /** Destroy Codestream information after compression or decompression @param cstr_info Codestream information structure */ OPJ_API void OPJ_CALLCONV opj_destroy_cstr_info(opj_codestream_info_t *cstr_info); +//============================================================================== +//============================================================================== +/** profiling part */ +#ifdef _PROFILE +void _ProfInit(void); +void _ProfPrint(void); +#define PROFINIT() _ProfInit(); +#define PROFSAVE(file) _ProfSave(file); +#define PROFPRINT() _ProfPrint(); +#else +#define PROFINIT() +#define PROFSAVE(file) +#define PROFPRINT() +#endif // !_PROFILE + #ifdef __cplusplus } #endif #endif /* OPENJPEG_H */ + + diff --git a/libopenjpeg/opj_configure.h b/libopenjpeg/opj_configure.h new file mode 100644 index 00000000..60058cbd --- /dev/null +++ b/libopenjpeg/opj_configure.h @@ -0,0 +1,16 @@ +/* + * here is where system comupted values get stored these values should only + * change when the target compile platform changes + */ + +/* what byte order */ +#ifndef __OPJ_CONFIGURE_H +#define __OPJ_CONFIGURE_H +/* #undef CMAKE_WORDS_BIGENDIAN */ +#ifdef CMAKE_WORDS_BIGENDIAN + #define OPJ_BIG_ENDIAN +#else + #define OPJ_LITTLE_ENDIAN +#endif + +#endif /* __OPJ_CONFIGURE_H */ diff --git a/libopenjpeg/opj_includes.h b/libopenjpeg/opj_includes.h index 80d43df9..d4ed1ae1 100644 --- a/libopenjpeg/opj_includes.h +++ b/libopenjpeg/opj_includes.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -40,13 +41,13 @@ #include <stdio.h> #include <stdarg.h> #include <ctype.h> +#include <assert.h> /* ========================================================== OpenJPEG interface ========================================================== */ -#include "openjpeg.h" /* ========================================================== @@ -100,33 +101,4 @@ static INLINE long lrintf(float f){ } #endif -#include "j2k_lib.h" -#include "opj_malloc.h" -#include "event.h" -#include "cio.h" - -#include "image.h" -#include "j2k.h" -#include "jp2.h" -#include "jpt.h" - -#include "mqc.h" -#include "raw.h" -#include "bio.h" -#include "tgt.h" -#include "pi.h" -#include "tcd.h" -#include "t1.h" -#include "dwt.h" -#include "t2.h" -#include "mct.h" -#include "int.h" -#include "fix.h" - -/* JPWL>> */ -#ifdef USE_JPWL -#include "../jpwl/jpwl.h" -#endif /* USE_JPWL */ -/* <<JPWL */ - #endif /* OPJ_INCLUDES_H */ diff --git a/libopenjpeg/opj_malloc.h b/libopenjpeg/opj_malloc.h index 9b48c256..92911181 100644 --- a/libopenjpeg/opj_malloc.h +++ b/libopenjpeg/opj_malloc.h @@ -1,140 +1,145 @@ -/*
- * Copyright (c) 2005, Hervé Drolon, FreeImage Team
- * Copyright (c) 2007, Callum Lerwick <seg@haxxed.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-#ifndef __OPJ_MALLOC_H
-#define __OPJ_MALLOC_H
-/**
-@file opj_malloc.h
-@brief Internal functions
-
-The functions in opj_malloc.h are internal utilities used for memory management.
-*/
-
-/** @defgroup MISC MISC - Miscellaneous internal functions */
-/*@{*/
-
-/** @name Exported functions */
-/*@{*/
-/* ----------------------------------------------------------------------- */
-
-/**
-Allocate an uninitialized memory block
-@param size Bytes to allocate
-@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available
-*/
-#define opj_malloc(size) malloc(size)
-
-/**
-Allocate a memory block with elements initialized to 0
-@param num Blocks to allocate
-@param size Bytes per block to allocate
-@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available
-*/
-#define opj_calloc(num, size) calloc(num, size)
-
-/**
-Allocate memory aligned to a 16 byte boundry
-@param size Bytes to allocate
-@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available
-*/
-/* FIXME: These should be set with cmake tests, but we're currently not requiring use of cmake */
-#ifdef WIN32
- /* Someone should tell the mingw people that their malloc.h ought to provide _mm_malloc() */
- #ifdef __GNUC__
- #include <mm_malloc.h>
- #define HAVE_MM_MALLOC
- #else /* MSVC, Intel C++ */
- #include <malloc.h>
- #ifdef _mm_malloc
- #define HAVE_MM_MALLOC
- #endif
- #endif
-#else /* Not WIN32 */
- #if defined(__sun)
- #define HAVE_MEMALIGN
- /* Linux x86_64 and OSX always align allocations to 16 bytes */
- #elif !defined(__amd64__) && !defined(__APPLE__)
- #define HAVE_MEMALIGN
- #include <malloc.h>
- #endif
-#endif
-
-#define opj_aligned_malloc(size) malloc(size)
-#define opj_aligned_free(m) free(m)
-
-#ifdef HAVE_MM_MALLOC
- #undef opj_aligned_malloc
- #define opj_aligned_malloc(size) _mm_malloc(size, 16)
- #undef opj_aligned_free
- #define opj_aligned_free(m) _mm_free(m)
-#endif
-
-#ifdef HAVE_MEMALIGN
- extern void* memalign(size_t, size_t);
- #undef opj_aligned_malloc
- #define opj_aligned_malloc(size) memalign(16, (size))
- #undef opj_aligned_free
- #define opj_aligned_free(m) free(m)
-#endif
-
-#ifdef HAVE_POSIX_MEMALIGN
- #undef opj_aligned_malloc
- extern int posix_memalign(void**, size_t, size_t);
-
- static INLINE void* __attribute__ ((malloc)) opj_aligned_malloc(size_t size){
- void* mem = NULL;
- posix_memalign(&mem, 16, size);
- return mem;
- }
- #undef opj_aligned_free
- #define opj_aligned_free(m) free(m)
-#endif
-
-/**
-Reallocate memory blocks.
-@param memblock Pointer to previously allocated memory block
-@param size New size in bytes
-@return Returns a void pointer to the reallocated (and possibly moved) memory block
-*/
-#define opj_realloc(m, s) realloc(m, s)
-
-/**
-Deallocates or frees a memory block.
-@param memblock Previously allocated memory block to be freed
-*/
-#define opj_free(m) free(m)
-
-#ifdef __GNUC__
-#pragma GCC poison malloc calloc realloc free
-#endif
-
-/* ----------------------------------------------------------------------- */
-/*@}*/
-
-/*@}*/
-
-#endif /* __OPJ_MALLOC_H */
-
+/* + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2007, Callum Lerwick <seg@haxxed.com> + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __OPJ_MALLOC_H +#define __OPJ_MALLOC_H +/** +@file opj_malloc.h +@brief Internal functions + +The functions in opj_malloc.h are internal utilities used for memory management. +*/ +#include "openjpeg.h" +#include "opj_includes.h" +/** @defgroup MISC MISC - Miscellaneous internal functions */ +/*@{*/ + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ + +/** +Allocate an uninitialized memory block +@param size Bytes to allocate +@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available +*/ +#define opj_malloc(size) malloc(size) +#define my_opj_malloc(size) malloc(size) + +/** +Allocate a memory block with elements initialized to 0 +@param num Blocks to allocate +@param size Bytes per block to allocate +@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available +*/ +#define opj_calloc(num, size) calloc(num, size) + +/** +Allocate memory aligned to a 16 byte boundry +@param size Bytes to allocate +@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available +*/ +/* FIXME: These should be set with cmake tests, but we're currently not requiring use of cmake */ +#ifdef WIN32 + /* Someone should tell the mingw people that their malloc.h ought to provide _mm_malloc() */ + #ifdef __GNUC__ + #include <mm_malloc.h> + #define HAVE_MM_MALLOC + #else /* MSVC, Intel C++ */ + #include <malloc.h> + #ifdef _mm_malloc + #define HAVE_MM_MALLOC + #endif + #endif +#else /* Not WIN32 */ + #if defined(__sun) + #define HAVE_MEMALIGN + /* Linux x86_64 and OSX always align allocations to 16 bytes */ + #elif !defined(__amd64__) && !defined(__APPLE__) + /* FIXME: Yes, this is a big assumption */ + #define HAVE_POSIX_MEMALIGN + #endif +#endif + +#define opj_aligned_malloc(size) malloc(size) +#define opj_aligned_free(m) free(m) + +#ifdef HAVE_MM_MALLOC + #undef opj_aligned_malloc + #define opj_aligned_malloc(size) _mm_malloc(size, 16) + #undef opj_aligned_free + #define opj_aligned_free(m) _mm_free(m) +#endif + +#ifdef HAVE_MEMALIGN + extern void* memalign(size_t, size_t); + #undef opj_aligned_malloc + #define opj_aligned_malloc(size) memalign(16, (size)) + #undef opj_aligned_free + #define opj_aligned_free(m) free(m) +#endif + +#ifdef HAVE_POSIX_MEMALIGN + #undef opj_aligned_malloc + extern int posix_memalign(void**, size_t, size_t); + + static INLINE void* __attribute__ ((malloc)) opj_aligned_malloc(size_t size){ + void* mem = NULL; + posix_memalign(&mem, 16, size); + return mem; + } + #undef opj_aligned_free + #define opj_aligned_free(m) free(m) +#endif + +/** +Reallocate memory blocks. +@param memblock Pointer to previously allocated memory block +@param size New size in bytes +@return Returns a void pointer to the reallocated (and possibly moved) memory block +*/ +#define opj_realloc(m, s) realloc(m, s) +#define my_opj_realloc(m,s) realloc(m,s) + + +/** +Deallocates or frees a memory block. +@param memblock Previously allocated memory block to be freed +*/ +#define opj_free(m) free(m) + +#ifdef __GNUC__ +#pragma GCC poison malloc calloc realloc free +#endif + +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __OPJ_MALLOC_H */ + diff --git a/libopenjpeg/pi.c b/libopenjpeg/pi.c index ac7654c5..97efc38b 100644 --- a/libopenjpeg/pi.c +++ b/libopenjpeg/pi.c @@ -6,6 +6,7 @@ * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe * Copyright (c) 2005, Herve Drolon, FreeImage Team * Copyright (c) 2006-2007, Parvatha Elangovan + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,8 +31,10 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "opj_includes.h" - +#include "pi.h" +#include "int.h" +#include "opj_malloc.h" +#include "j2k.h" /** @defgroup PI PI - Implementation of a packet iterator */ /*@{*/ @@ -69,6 +72,139 @@ Get next packet in component-precinct-resolution-layer order. */ static bool pi_next_cprl(opj_pi_iterator_t * pi); +/** + * Updates the coding parameters if the encoding is used with Progression order changes and final (or cinema parameters are used). + * + * @param p_cp the coding parameters to modify + * @param p_tileno the tile index being concerned. + * @param p_tx0 X0 parameter for the tile + * @param p_tx1 X1 parameter for the tile + * @param p_ty0 Y0 parameter for the tile + * @param p_ty1 Y1 parameter for the tile + * @param p_max_prec the maximum precision for all the bands of the tile + * @param p_max_res the maximum number of resolutions for all the poc inside the tile. + * @param dx_min the minimum dx of all the components of all the resolutions for the tile. + * @param dy_min the minimum dy of all the components of all the resolutions for the tile. + */ +void pi_update_encode_poc_and_final ( + opj_cp_t *p_cp, + OPJ_UINT32 p_tileno, + OPJ_INT32 p_tx0, + OPJ_INT32 p_tx1, + OPJ_INT32 p_ty0, + OPJ_INT32 p_ty1, + OPJ_UINT32 p_max_prec, + OPJ_UINT32 p_max_res, + OPJ_UINT32 p_dx_min, + OPJ_UINT32 p_dy_min); + +/** + * Updates the coding parameters if the encoding is not used with Progression order changes and final (and cinema parameters are used). + * + * @param p_cp the coding parameters to modify + * @param p_tileno the tile index being concerned. + * @param p_tx0 X0 parameter for the tile + * @param p_tx1 X1 parameter for the tile + * @param p_ty0 Y0 parameter for the tile + * @param p_ty1 Y1 parameter for the tile + * @param p_max_prec the maximum precision for all the bands of the tile + * @param p_max_res the maximum number of resolutions for all the poc inside the tile. + * @param dx_min the minimum dx of all the components of all the resolutions for the tile. + * @param dy_min the minimum dy of all the components of all the resolutions for the tile. + */ +void pi_update_encode_not_poc ( + opj_cp_t *p_cp, + OPJ_UINT32 p_num_comps, + OPJ_UINT32 p_tileno, + OPJ_INT32 p_tx0, + OPJ_INT32 p_tx1, + OPJ_INT32 p_ty0, + OPJ_INT32 p_ty1, + OPJ_UINT32 p_max_prec, + OPJ_UINT32 p_max_res, + OPJ_UINT32 p_dx_min, + OPJ_UINT32 p_dy_min); + +/** + * Gets the encoding parameters needed to update the coding parameters and all the pocs. + * + * @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. + */ +void get_encoding_parameters( + const opj_image_t *p_image, + const opj_cp_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 + ); + +/** + * 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_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 + ); +/** + * 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_t *cp, + OPJ_UINT32 tileno + ); +void pi_update_decode_not_poc (opj_pi_iterator_t * p_pi,opj_tcp_t * p_tcp,OPJ_UINT32 p_max_precision,OPJ_UINT32 p_max_res); +void pi_update_decode_poc (opj_pi_iterator_t * p_pi,opj_tcp_t * p_tcp,OPJ_UINT32 p_max_precision,OPJ_UINT32 p_max_res); + + /*@}*/ /*@}*/ @@ -80,9 +216,9 @@ static bool pi_next_cprl(opj_pi_iterator_t * pi); */ static bool pi_next_lrcp(opj_pi_iterator_t * pi) { - opj_pi_comp_t *comp = NULL; - opj_pi_resolution_t *res = NULL; - long index = 0; + opj_pi_comp_t *comp = 00; + opj_pi_resolution_t *res = 00; + OPJ_UINT32 index = 0; if (!pi->first) { comp = &pi->comps[pi->compno]; @@ -120,9 +256,9 @@ LABEL_SKIP:; } static bool pi_next_rlcp(opj_pi_iterator_t * pi) { - opj_pi_comp_t *comp = NULL; - opj_pi_resolution_t *res = NULL; - long index = 0; + opj_pi_comp_t *comp = 00; + opj_pi_resolution_t *res = 00; + OPJ_UINT32 index = 0; if (!pi->first) { comp = &pi->comps[pi->compno]; @@ -159,21 +295,21 @@ LABEL_SKIP:; } static bool pi_next_rpcl(opj_pi_iterator_t * pi) { - opj_pi_comp_t *comp = NULL; - opj_pi_resolution_t *res = NULL; - long index = 0; + opj_pi_comp_t *comp = 00; + opj_pi_resolution_t *res = 00; + OPJ_UINT32 index = 0; if (!pi->first) { goto LABEL_SKIP; } else { - int compno, resno; + OPJ_UINT32 compno, resno; pi->first = 0; pi->dx = 0; pi->dy = 0; for (compno = 0; compno < pi->numcomps; compno++) { comp = &pi->comps[compno]; for (resno = 0; resno < comp->numresolutions; resno++) { - int dx, dy; + OPJ_UINT32 dx, dy; res = &comp->resolutions[resno]; dx = comp->dx * (1 << (res->pdx + comp->numresolutions - 1 - resno)); dy = comp->dy * (1 << (res->pdy + comp->numresolutions - 1 - resno)); @@ -192,11 +328,11 @@ if (!pi->tp_on){ for (pi->y = pi->poc.ty0; pi->y < pi->poc.ty1; pi->y += pi->dy - (pi->y % pi->dy)) { for (pi->x = pi->poc.tx0; pi->x < pi->poc.tx1; pi->x += pi->dx - (pi->x % pi->dx)) { for (pi->compno = pi->poc.compno0; pi->compno < pi->poc.compno1; pi->compno++) { - int levelno; - int trx0, try0; - int trx1, try1; - int rpx, rpy; - int prci, prcj; + OPJ_UINT32 levelno; + OPJ_INT32 trx0, try0; + OPJ_INT32 trx1, try1; + OPJ_UINT32 rpx, rpy; + OPJ_INT32 prci, prcj; comp = &pi->comps[pi->compno]; if (pi->resno >= comp->numresolutions) { continue; @@ -216,7 +352,7 @@ if (!pi->tp_on){ continue; } - if ((res->pw==0)||(res->pw==0)) continue; + if ((res->pw==0)||(res->ph==0)) continue; if ((trx0==trx1)||(try0==try1)) continue; @@ -242,22 +378,22 @@ LABEL_SKIP:; } static bool pi_next_pcrl(opj_pi_iterator_t * pi) { - opj_pi_comp_t *comp = NULL; - opj_pi_resolution_t *res = NULL; - long index = 0; + opj_pi_comp_t *comp = 00; + opj_pi_resolution_t *res = 00; + OPJ_UINT32 index = 0; if (!pi->first) { comp = &pi->comps[pi->compno]; goto LABEL_SKIP; } else { - int compno, resno; + OPJ_UINT32 compno, resno; pi->first = 0; pi->dx = 0; pi->dy = 0; for (compno = 0; compno < pi->numcomps; compno++) { comp = &pi->comps[compno]; for (resno = 0; resno < comp->numresolutions; resno++) { - int dx, dy; + OPJ_UINT32 dx, dy; res = &comp->resolutions[resno]; dx = comp->dx * (1 << (res->pdx + comp->numresolutions - 1 - resno)); dy = comp->dy * (1 << (res->pdy + comp->numresolutions - 1 - resno)); @@ -276,12 +412,13 @@ static bool pi_next_pcrl(opj_pi_iterator_t * pi) { for (pi->x = pi->poc.tx0; pi->x < pi->poc.tx1; pi->x += pi->dx - (pi->x % pi->dx)) { for (pi->compno = pi->poc.compno0; pi->compno < pi->poc.compno1; pi->compno++) { comp = &pi->comps[pi->compno]; - for (pi->resno = pi->poc.resno0; pi->resno < int_min(pi->poc.resno1, comp->numresolutions); pi->resno++) { - int levelno; - int trx0, try0; - int trx1, try1; - int rpx, rpy; - int prci, prcj; + // TODO + for (pi->resno = pi->poc.resno0; pi->resno < uint_min(pi->poc.resno1, comp->numresolutions); pi->resno++) { + OPJ_UINT32 levelno; + OPJ_INT32 trx0, try0; + OPJ_INT32 trx1, try1; + OPJ_UINT32 rpx, rpy; + OPJ_INT32 prci, prcj; res = &comp->resolutions[pi->resno]; levelno = comp->numresolutions - 1 - pi->resno; trx0 = int_ceildiv(pi->tx0, comp->dx << levelno); @@ -297,7 +434,7 @@ static bool pi_next_pcrl(opj_pi_iterator_t * pi) { continue; } - if ((res->pw==0)||(res->pw==0)) continue; + if ((res->pw==0)||(res->ph==0)) continue; if ((trx0==trx1)||(try0==try1)) continue; @@ -323,9 +460,9 @@ LABEL_SKIP:; } static bool pi_next_cprl(opj_pi_iterator_t * pi) { - opj_pi_comp_t *comp = NULL; - opj_pi_resolution_t *res = NULL; - long index = 0; + opj_pi_comp_t *comp = 00; + opj_pi_resolution_t *res = 00; + OPJ_UINT32 index = 0; if (!pi->first) { comp = &pi->comps[pi->compno]; @@ -335,12 +472,12 @@ static bool pi_next_cprl(opj_pi_iterator_t * pi) { } for (pi->compno = pi->poc.compno0; pi->compno < pi->poc.compno1; pi->compno++) { - int resno; + OPJ_UINT32 resno; comp = &pi->comps[pi->compno]; pi->dx = 0; pi->dy = 0; for (resno = 0; resno < comp->numresolutions; resno++) { - int dx, dy; + OPJ_UINT32 dx, dy; res = &comp->resolutions[resno]; dx = comp->dx * (1 << (res->pdx + comp->numresolutions - 1 - resno)); dy = comp->dy * (1 << (res->pdy + comp->numresolutions - 1 - resno)); @@ -355,12 +492,13 @@ static bool pi_next_cprl(opj_pi_iterator_t * pi) { } for (pi->y = pi->poc.ty0; pi->y < pi->poc.ty1; pi->y += pi->dy - (pi->y % pi->dy)) { for (pi->x = pi->poc.tx0; pi->x < pi->poc.tx1; pi->x += pi->dx - (pi->x % pi->dx)) { - for (pi->resno = pi->poc.resno0; pi->resno < int_min(pi->poc.resno1, comp->numresolutions); pi->resno++) { - int levelno; - int trx0, try0; - int trx1, try1; - int rpx, rpy; - int prci, prcj; + // TODO + for (pi->resno = pi->poc.resno0; pi->resno < uint_min(pi->poc.resno1, comp->numresolutions); pi->resno++) { + OPJ_UINT32 levelno; + OPJ_INT32 trx0, try0; + OPJ_INT32 trx1, try1; + OPJ_UINT32 rpx, rpy; + OPJ_INT32 prci, prcj; res = &comp->resolutions[pi->resno]; levelno = comp->numresolutions - 1 - pi->resno; trx0 = int_ceildiv(pi->tx0, comp->dx << levelno); @@ -406,304 +544,1095 @@ LABEL_SKIP:; Packet iterator interface ========================================================== */ +opj_pi_iterator_t *pi_create_decode( + opj_image_t *p_image, + opj_cp_t *p_cp, + OPJ_UINT32 p_tile_no + ) +{ + // loop + OPJ_UINT32 pino; + OPJ_UINT32 compno, resno; + + // to store w, h, dx and dy fro all components and resolutions + OPJ_UINT32 * l_tmp_data; + OPJ_UINT32 ** l_tmp_ptr; + + // encoding prameters to set + OPJ_UINT32 l_max_res; + OPJ_UINT32 l_max_prec; + OPJ_INT32 l_tx0,l_tx1,l_ty0,l_ty1; + OPJ_UINT32 l_dx_min,l_dy_min; + OPJ_UINT32 l_bound; + OPJ_UINT32 l_step_p , l_step_c , l_step_r , l_step_l ; + OPJ_UINT32 l_data_stride; -opj_pi_iterator_t *pi_create_decode(opj_image_t *image, opj_cp_t *cp, int tileno) { - int p, q; - int compno, resno, pino; - opj_pi_iterator_t *pi = NULL; - opj_tcp_t *tcp = NULL; - opj_tccp_t *tccp = NULL; + // pointers + opj_pi_iterator_t *l_pi = 00; + opj_tcp_t *l_tcp = 00; + const opj_tccp_t *l_tccp = 00; + opj_pi_comp_t *l_current_comp = 00; + opj_image_comp_t * l_img_comp = 00; + opj_pi_iterator_t * l_current_pi = 00; + OPJ_UINT32 * l_encoding_value_ptr = 00; + + // preconditions in debug + assert(p_cp != 00); + assert(p_image != 00); + assert(p_tile_no < p_cp->tw * p_cp->th); - tcp = &cp->tcps[tileno]; + // 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_malloc(l_data_stride * p_image->numcomps * sizeof(OPJ_UINT32)); + if + (! l_tmp_data) + { + return 00; + } + l_tmp_ptr = opj_malloc(p_image->numcomps * sizeof(OPJ_UINT32 *)); + if + (! l_tmp_ptr) + { + opj_free(l_tmp_data); + return 00; + } - pi = (opj_pi_iterator_t*) opj_calloc((tcp->numpocs + 1), sizeof(opj_pi_iterator_t)); - if(!pi) { - /* TODO: throw an error */ - return NULL; - } - - for (pino = 0; pino < tcp->numpocs + 1; pino++) { /* change */ - int maxres = 0; - int maxprec = 0; - p = tileno % cp->tw; - q = tileno / cp->tw; - - pi[pino].tx0 = int_max(cp->tx0 + p * cp->tdx, image->x0); - pi[pino].ty0 = int_max(cp->ty0 + q * cp->tdy, image->y0); - pi[pino].tx1 = int_min(cp->tx0 + (p + 1) * cp->tdx, image->x1); - pi[pino].ty1 = int_min(cp->ty0 + (q + 1) * cp->tdy, image->y1); - pi[pino].numcomps = image->numcomps; - - pi[pino].comps = (opj_pi_comp_t*) opj_calloc(image->numcomps, sizeof(opj_pi_comp_t)); - if(!pi[pino].comps) { - /* TODO: throw an error */ - pi_destroy(pi, cp, tileno); - return NULL; - } - - for (compno = 0; compno < pi->numcomps; compno++) { - int tcx0, tcy0, tcx1, tcy1; - opj_pi_comp_t *comp = &pi[pino].comps[compno]; - tccp = &tcp->tccps[compno]; - comp->dx = image->comps[compno].dx; - comp->dy = image->comps[compno].dy; - comp->numresolutions = tccp->numresolutions; + // 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; - comp->resolutions = (opj_pi_resolution_t*) opj_calloc(comp->numresolutions, sizeof(opj_pi_resolution_t)); - if(!comp->resolutions) { - /* TODO: throw an error */ - pi_destroy(pi, cp, tileno); - return NULL; - } + // 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(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; - tcx0 = int_ceildiv(pi->tx0, comp->dx); - tcy0 = int_ceildiv(pi->ty0, comp->dy); - tcx1 = int_ceildiv(pi->tx1, comp->dx); - tcy1 = int_ceildiv(pi->ty1, comp->dy); - if (comp->numresolutions > maxres) { - maxres = comp->numresolutions; - } + 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; - for (resno = 0; resno < comp->numresolutions; resno++) { - int levelno; - int rx0, ry0, rx1, ry1; - int px0, py0, px1, py1; - opj_pi_resolution_t *res = &comp->resolutions[resno]; - if (tccp->csty & J2K_CCP_CSTY_PRT) { - res->pdx = tccp->prcw[resno]; - res->pdy = tccp->prch[resno]; - } else { - res->pdx = 15; - res->pdy = 15; - } - levelno = comp->numresolutions - 1 - resno; - rx0 = int_ceildivpow2(tcx0, levelno); - ry0 = int_ceildivpow2(tcy0, levelno); - rx1 = int_ceildivpow2(tcx1, levelno); - ry1 = int_ceildivpow2(tcy1, levelno); - px0 = int_floordivpow2(rx0, res->pdx) << res->pdx; - py0 = int_floordivpow2(ry0, res->pdy) << res->pdy; - px1 = int_ceildivpow2(rx1, res->pdx) << res->pdx; - py1 = int_ceildivpow2(ry1, res->pdy) << res->pdy; - res->pw = (rx0==rx1)?0:((px1 - px0) >> res->pdx); - res->ph = (ry0==ry1)?0:((py1 - py0) >> res->pdy); - - if (res->pw*res->ph > maxprec) { - maxprec = res->pw*res->ph; - } - - } + /* 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; } - - tccp = &tcp->tccps[0]; - pi[pino].step_p = 1; - pi[pino].step_c = maxprec * pi[pino].step_p; - pi[pino].step_r = image->numcomps * pi[pino].step_c; - pi[pino].step_l = maxres * pi[pino].step_r; - - if (pino == 0) { - pi[pino].include = (short int*) opj_calloc(image->numcomps * maxres * tcp->numlayers * maxprec, sizeof(short int)); - if(!pi[pino].include) { - /* TODO: throw an error */ - pi_destroy(pi, cp, tileno); - return NULL; + ++l_current_comp; + ++l_img_comp; + ++l_tccp; + } + ++l_current_pi; + + for + (pino = 1 ; pino<l_bound ; ++pino ) + { + opj_pi_comp_t *l_current_comp = l_current_pi->comps; + 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; } - else { - pi[pino].include = pi[pino - 1].include; - } - - if (tcp->POC == 0) { - pi[pino].first = 1; - pi[pino].poc.resno0 = 0; - pi[pino].poc.compno0 = 0; - pi[pino].poc.layno1 = tcp->numlayers; - pi[pino].poc.resno1 = maxres; - pi[pino].poc.compno1 = image->numcomps; - pi[pino].poc.prg = tcp->prg; - } else { - pi[pino].first = 1; - pi[pino].poc.resno0 = tcp->pocs[pino].resno0; - pi[pino].poc.compno0 = tcp->pocs[pino].compno0; - pi[pino].poc.layno1 = tcp->pocs[pino].layno1; - pi[pino].poc.resno1 = tcp->pocs[pino].resno1; - pi[pino].poc.compno1 = tcp->pocs[pino].compno1; - pi[pino].poc.prg = tcp->pocs[pino].prg; - } - pi[pino].poc.layno0 = 0; - pi[pino].poc.precno0 = 0; - pi[pino].poc.precno1 = maxprec; - + // 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; +} + +void pi_update_decode_poc (opj_pi_iterator_t * p_pi,opj_tcp_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; - return pi; + // 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;pino<l_bound;++pino) + { + l_current_pi->poc.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_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; -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; - int maxres = 0; - int maxprec = 0; - opj_pi_iterator_t *pi = NULL; - opj_tcp_t *tcp = NULL; - opj_tccp_t *tccp = NULL; + for + (pino = 0;pino<l_bound;++pino) + { + l_current_pi->poc.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; + } +} + +/** + * Creates a packet iterator for encoding. + * + * @param p_image the image being encoded. + * @param p_cp the coding parameters. + * @param p_tile_no index of the tile being encoded. + * @param p_t2_mode the type of pass for generating the packet iterator + * @return a list of packet iterator that points to the first packet of the tile (not true). +*/ +opj_pi_iterator_t *pi_initialise_encode( + const opj_image_t *p_image, + opj_cp_t *p_cp, + OPJ_UINT32 p_tile_no, + J2K_T2_MODE p_t2_mode + ) +{ + // loop + OPJ_UINT32 pino; + OPJ_UINT32 compno, resno; - tcp = &cp->tcps[tileno]; + // to store w, h, dx and dy fro all components and resolutions + OPJ_UINT32 * l_tmp_data; + OPJ_UINT32 ** l_tmp_ptr; + + // encoding prameters to set + OPJ_UINT32 l_max_res; + OPJ_UINT32 l_max_prec; + OPJ_INT32 l_tx0,l_tx1,l_ty0,l_ty1; + OPJ_UINT32 l_dx_min,l_dy_min; + OPJ_UINT32 l_bound; + OPJ_UINT32 l_step_p , l_step_c , l_step_r , l_step_l ; + OPJ_UINT32 l_data_stride; - pi = (opj_pi_iterator_t*) opj_calloc((tcp->numpocs + 1), sizeof(opj_pi_iterator_t)); - if(!pi) { return NULL;} - pi->tp_on = cp->tp_on; + // pointers + opj_pi_iterator_t *l_pi = 00; + opj_tcp_t *l_tcp = 00; + const opj_tccp_t *l_tccp = 00; + opj_pi_comp_t *l_current_comp = 00; + opj_image_comp_t * l_img_comp = 00; + opj_pi_iterator_t * l_current_pi = 00; + OPJ_UINT32 * l_encoding_value_ptr = 00; + + // preconditions in debug + assert(p_cp != 00); + assert(p_image != 00); + assert(p_tile_no < p_cp->tw * p_cp->th); - for(pino = 0;pino < tcp->numpocs+1 ; pino ++){ - p = tileno % cp->tw; - q = tileno / cp->tw; + // 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_malloc(l_data_stride * p_image->numcomps * sizeof(OPJ_UINT32)); + if + (! l_tmp_data) + { + return 00; + } + l_tmp_ptr = opj_malloc(p_image->numcomps * sizeof(OPJ_UINT32 *)); + if + (! l_tmp_ptr) + { + opj_free(l_tmp_data); + return 00; + } - pi[pino].tx0 = int_max(cp->tx0 + p * cp->tdx, image->x0); - pi[pino].ty0 = int_max(cp->ty0 + q * cp->tdy, image->y0); - pi[pino].tx1 = int_min(cp->tx0 + (p + 1) * cp->tdx, image->x1); - pi[pino].ty1 = int_min(cp->ty0 + (q + 1) * cp->tdy, image->y1); - pi[pino].numcomps = image->numcomps; - - pi[pino].comps = (opj_pi_comp_t*) opj_calloc(image->numcomps, sizeof(opj_pi_comp_t)); - if(!pi[pino].comps) { - pi_destroy(pi, cp, tileno); - return NULL; + // 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_pi->tp_on = p_cp->m_specific_param.m_enc.m_tp_on; + 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(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_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; } - - for (compno = 0; compno < pi[pino].numcomps; compno++) { - int tcx0, tcy0, tcx1, tcy1; - opj_pi_comp_t *comp = &pi[pino].comps[compno]; - tccp = &tcp->tccps[compno]; - comp->dx = image->comps[compno].dx; - comp->dy = image->comps[compno].dy; - comp->numresolutions = tccp->numresolutions; + ++l_current_comp; + ++l_img_comp; + ++l_tccp; + } + ++l_current_pi; + + for + (pino = 1 ; pino<l_bound ; ++pino ) + { + opj_pi_comp_t *l_current_comp = l_current_pi->comps; + opj_image_comp_t * l_img_comp = p_image->comps; + l_tccp = l_tcp->tccps; - comp->resolutions = (opj_pi_resolution_t*) opj_malloc(comp->numresolutions * sizeof(opj_pi_resolution_t)); - if(!comp->resolutions) { - pi_destroy(pi, cp, tileno); - return NULL; - } + 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; - tcx0 = int_ceildiv(pi[pino].tx0, comp->dx); - tcy0 = int_ceildiv(pi[pino].ty0, comp->dy); - tcx1 = int_ceildiv(pi[pino].tx1, comp->dx); - tcy1 = int_ceildiv(pi[pino].ty1, comp->dy); - if (comp->numresolutions > maxres) { - maxres = comp->numresolutions; + /* 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 && ( p_cp->m_specific_param.m_enc.m_cinema || p_t2_mode == FINAL_PASS)) + { + pi_update_encode_poc_and_final(p_cp,p_tile_no,l_tx0,l_tx1,l_ty0,l_ty1,l_max_prec,l_max_res,l_dx_min,l_dy_min); + } + else + { + pi_update_encode_not_poc(p_cp,p_image->numcomps,p_tile_no,l_tx0,l_tx1,l_ty0,l_ty1,l_max_prec,l_max_res,l_dx_min,l_dy_min); + } + return l_pi; +} - for (resno = 0; resno < comp->numresolutions; resno++) { - int levelno; - int rx0, ry0, rx1, ry1; - int px0, py0, px1, py1; - opj_pi_resolution_t *res = &comp->resolutions[resno]; - if (tccp->csty & J2K_CCP_CSTY_PRT) { - res->pdx = tccp->prcw[resno]; - res->pdy = tccp->prch[resno]; - } else { - res->pdx = 15; - res->pdy = 15; - } - levelno = comp->numresolutions - 1 - resno; - rx0 = int_ceildivpow2(tcx0, levelno); - ry0 = int_ceildivpow2(tcy0, levelno); - rx1 = int_ceildivpow2(tcx1, levelno); - ry1 = int_ceildivpow2(tcy1, levelno); - px0 = int_floordivpow2(rx0, res->pdx) << res->pdx; - py0 = int_floordivpow2(ry0, res->pdy) << res->pdy; - px1 = int_ceildivpow2(rx1, res->pdx) << res->pdx; - py1 = int_ceildivpow2(ry1, res->pdy) << res->pdy; - res->pw = (rx0==rx1)?0:((px1 - px0) >> res->pdx); - res->ph = (ry0==ry1)?0:((py1 - py0) >> res->pdy); - - if (res->pw*res->ph > maxprec) { - maxprec = res->pw * res->ph; - } +/** + * Updates the encoding parameters of the codec. + * + * @param p_image the image being encoded. + * @param p_cp the coding parameters. + * @param p_tile_no index of the tile being encoded. +*/ +void pi_update_encoding_parameters( + const opj_image_t *p_image, + opj_cp_t *p_cp, + OPJ_UINT32 p_tile_no + ) +{ + // encoding prameters to set + OPJ_UINT32 l_max_res; + OPJ_UINT32 l_max_prec; + OPJ_INT32 l_tx0,l_tx1,l_ty0,l_ty1; + OPJ_UINT32 l_dx_min,l_dy_min; + + // pointers + opj_tcp_t *l_tcp = 00; + + // preconditions in debug + assert(p_cp != 00); + assert(p_image != 00); + assert(p_tile_no < p_cp->tw * p_cp->th); + + l_tcp = &(p_cp->tcps[p_tile_no]); + // get encoding parameters + get_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); + if + (l_tcp->POC) + { + pi_update_encode_poc_and_final(p_cp,p_tile_no,l_tx0,l_tx1,l_ty0,l_ty1,l_max_prec,l_max_res,l_dx_min,l_dy_min); + } + else + { + pi_update_encode_not_poc(p_cp,p_image->numcomps,p_tile_no,l_tx0,l_tx1,l_ty0,l_ty1,l_max_prec,l_max_res,l_dx_min,l_dy_min); + } +} + + +/** + * Gets the encoding parameters needed to update the coding parameters and all the pocs. + * + * @param p_image the image being encoded. + * @param p_cp the coding parameters. + * @param p_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. + */ +void get_encoding_parameters( + const opj_image_t *p_image, + const opj_cp_t *p_cp, + OPJ_UINT32 p_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 + ) +{ + // loop + OPJ_UINT32 compno, resno; + // pointers + const opj_tcp_t *l_tcp = 00; + const opj_tccp_t * l_tccp = 00; + const opj_image_comp_t * l_img_comp = 00; + + // position in x and y of tile + OPJ_UINT32 p, q; + + // preconditions in debug + assert(p_cp != 00); + assert(p_image != 00); + assert(p_tileno < p_cp->tw * p_cp->th); + + // initializations + l_tcp = &p_cp->tcps [p_tileno]; + l_img_comp = p_image->comps; + l_tccp = l_tcp->tccps; + + /* here calculation of tx0, tx1, ty0, ty1, maxprec, dx and dy */ + p = p_tileno % p_cp->tw; + q = p_tileno / p_cp->tw; + + // find extent of tile + *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 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_pdx, l_pdy; + OPJ_UINT32 l_pw, l_ph; + OPJ_UINT32 l_product; + OPJ_INT32 l_tcx0, l_tcy0, l_tcx1, l_tcy1; + + 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 + 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]; + + l_dx = l_img_comp->dx * (1 << (l_pdx + l_tccp->numresolutions - 1 - resno)); + l_dy = l_img_comp->dy * (1 << (l_pdy + l_tccp->numresolutions - 1 - resno)); + // take the minimum size for dx for each comp and resolution + *p_dx_min = uint_min(*p_dx_min, l_dx); + *p_dy_min = uint_min(*p_dy_min, l_dy); + // various calculations of extents + l_level_no = l_tccp->numresolutions - 1 - resno; + 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); + l_product = l_pw * l_ph; + // update precision + if + (l_product > *p_max_prec) + { + *p_max_prec = l_product; } } + ++l_img_comp; + ++l_tccp; + } +} + +/** + * 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_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_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]; - tccp = &tcp->tccps[0]; - pi[pino].step_p = 1; - pi[pino].step_c = maxprec * pi[pino].step_p; - pi[pino].step_r = image->numcomps * pi[pino].step_c; - pi[pino].step_l = maxres * pi[pino].step_r; - - for (compno = 0; compno < pi->numcomps; compno++) { - opj_pi_comp_t *comp = &pi->comps[compno]; - for (resno = 0; resno < comp->numresolutions; resno++) { - int dx, dy; - opj_pi_resolution_t *res = &comp->resolutions[resno]; - dx = comp->dx * (1 << (res->pdx + comp->numresolutions - 1 - resno)); - dy = comp->dy * (1 << (res->pdy + comp->numresolutions - 1 - resno)); - pi[pino].dx = !pi->dx ? dx : int_min(pi->dx, dx); - pi[pino].dy = !pi->dy ? dy : int_min(pi->dy, dy); - } + 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; } - if (pino == 0) { - pi[pino].include = (short int*) opj_calloc(tcp->numlayers * pi[pino].step_l, sizeof(short int)); - if(!pi[pino].include) { - pi_destroy(pi, cp, tileno); - return NULL; + // 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; } - else { - pi[pino].include = pi[pino - 1].include; + ++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_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_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(l_pi, l_poc_bound); + return 00; } - - /* Generation of boundaries for each prog flag*/ - if(tcp->POC && ( cp->cinema || ((!cp->cinema) && (t2_mode == FINAL_PASS)))){ - tcp->pocs[pino].compS= tcp->pocs[pino].compno0; - tcp->pocs[pino].compE= tcp->pocs[pino].compno1; - tcp->pocs[pino].resS = tcp->pocs[pino].resno0; - tcp->pocs[pino].resE = tcp->pocs[pino].resno1; - tcp->pocs[pino].layE = tcp->pocs[pino].layno1; - tcp->pocs[pino].prg = tcp->pocs[pino].prg1; - if (pino > 0) - tcp->pocs[pino].layS = (tcp->pocs[pino].layE > tcp->pocs[pino - 1].layE) ? tcp->pocs[pino - 1].layE : 0; - }else { - tcp->pocs[pino].compS= 0; - tcp->pocs[pino].compE= image->numcomps; - tcp->pocs[pino].resS = 0; - tcp->pocs[pino].resE = maxres; - tcp->pocs[pino].layS = 0; - tcp->pocs[pino].layE = tcp->numlayers; - tcp->pocs[pino].prg = tcp->prg; + 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(l_pi, l_poc_bound); + return 00; } - tcp->pocs[pino].prcS = 0; - tcp->pocs[pino].prcE = maxprec;; - tcp->pocs[pino].txS = pi[pino].tx0; - tcp->pocs[pino].txE = pi[pino].tx1; - tcp->pocs[pino].tyS = pi[pino].ty0; - tcp->pocs[pino].tyE = pi[pino].ty1; - tcp->pocs[pino].dx = pi[pino].dx; - tcp->pocs[pino].dy = pi[pino].dy; + comp->numresolutions = tccp->numresolutions; + memset(comp->resolutions,0,tccp->numresolutions * sizeof(opj_pi_resolution_t)); } - return pi; + ++l_current_pi; + } + return l_pi; +} + +/** + * Updates the coding parameters if the encoding is used with Progression order changes and final (or cinema parameters are used). + * + * @param p_cp the coding parameters to modify + * @param p_tileno the tile index being concerned. + * @param p_tx0 X0 parameter for the tile + * @param p_tx1 X1 parameter for the tile + * @param p_ty0 Y0 parameter for the tile + * @param p_ty1 Y1 parameter for the tile + * @param p_max_prec the maximum precision for all the bands of the tile + * @param p_max_res the maximum number of resolutions for all the poc inside the tile. + * @param dx_min the minimum dx of all the components of all the resolutions for the tile. + * @param dy_min the minimum dy of all the components of all the resolutions for the tile. + */ +void pi_update_encode_poc_and_final ( + opj_cp_t *p_cp, + OPJ_UINT32 p_tileno, + OPJ_INT32 p_tx0, + OPJ_INT32 p_tx1, + OPJ_INT32 p_ty0, + OPJ_INT32 p_ty1, + OPJ_UINT32 p_max_prec, + OPJ_UINT32 p_max_res, + OPJ_UINT32 p_dx_min, + OPJ_UINT32 p_dy_min) +{ + // loop + OPJ_UINT32 pino; + // tile coding parameter + opj_tcp_t *l_tcp = 00; + // current poc being updated + opj_poc_t * l_current_poc = 00; + + // number of pocs + OPJ_UINT32 l_poc_bound; + + // preconditions in debug + assert(p_cp != 00); + assert(p_tileno < p_cp->tw * p_cp->th); + + // initializations + l_tcp = &p_cp->tcps [p_tileno]; + /* number of iterations in the loop */ + l_poc_bound = l_tcp->numpocs+1; + + // start at first element, and to make sure the compiler will not make a calculation each time in the loop + // store a pointer to the current element to modify rather than l_tcp->pocs[i] + l_current_poc = l_tcp->pocs; + + l_current_poc->compS = l_current_poc->compno0; + l_current_poc->compE = l_current_poc->compno1; + l_current_poc->resS = l_current_poc->resno0; + l_current_poc->resE = l_current_poc->resno1; + l_current_poc->layE = l_current_poc->layno1; + + // special treatment for the first element + l_current_poc->layS = 0; + l_current_poc->prg = l_current_poc->prg1; + l_current_poc->prcS = 0; + + l_current_poc->prcE = p_max_prec; + l_current_poc->txS = p_tx0; + l_current_poc->txE = p_tx1; + l_current_poc->tyS = p_ty0; + l_current_poc->tyE = p_ty1; + l_current_poc->dx = p_dx_min; + l_current_poc->dy = p_dy_min; + + ++ l_current_poc; + for + (pino = 1;pino < l_poc_bound ; ++pino) + { + l_current_poc->compS = l_current_poc->compno0; + l_current_poc->compE= l_current_poc->compno1; + l_current_poc->resS = l_current_poc->resno0; + l_current_poc->resE = l_current_poc->resno1; + l_current_poc->layE = l_current_poc->layno1; + l_current_poc->prg = l_current_poc->prg1; + l_current_poc->prcS = 0; + // special treatment here different from the first element + l_current_poc->layS = (l_current_poc->layE > (l_current_poc-1)->layE) ? l_current_poc->layE : 0; + + l_current_poc->prcE = p_max_prec; + l_current_poc->txS = p_tx0; + l_current_poc->txE = p_tx1; + l_current_poc->tyS = p_ty0; + l_current_poc->tyE = p_ty1; + l_current_poc->dx = p_dx_min; + l_current_poc->dy = p_dy_min; + ++ l_current_poc; } +} +/** + * Updates the coding parameters if the encoding is not used with Progression order changes and final (and cinema parameters are used). + * + * @param p_cp the coding parameters to modify + * @param p_tileno the tile index being concerned. + * @param p_tx0 X0 parameter for the tile + * @param p_tx1 X1 parameter for the tile + * @param p_ty0 Y0 parameter for the tile + * @param p_ty1 Y1 parameter for the tile + * @param p_max_prec the maximum precision for all the bands of the tile + * @param p_max_res the maximum number of resolutions for all the poc inside the tile. + * @param dx_min the minimum dx of all the components of all the resolutions for the tile. + * @param dy_min the minimum dy of all the components of all the resolutions for the tile. + */ +void pi_update_encode_not_poc ( + opj_cp_t *p_cp, + OPJ_UINT32 p_num_comps, + OPJ_UINT32 p_tileno, + OPJ_INT32 p_tx0, + OPJ_INT32 p_tx1, + OPJ_INT32 p_ty0, + OPJ_INT32 p_ty1, + OPJ_UINT32 p_max_prec, + OPJ_UINT32 p_max_res, + OPJ_UINT32 p_dx_min, + OPJ_UINT32 p_dy_min) +{ + // loop + OPJ_UINT32 pino; + // tile coding parameter + opj_tcp_t *l_tcp = 00; + // current poc being updated + opj_poc_t * l_current_poc = 00; + // number of pocs + OPJ_UINT32 l_poc_bound; + + // preconditions in debug + assert(p_cp != 00); + assert(p_tileno < p_cp->tw * p_cp->th); + + // initializations + l_tcp = &p_cp->tcps [p_tileno]; + + /* number of iterations in the loop */ + l_poc_bound = l_tcp->numpocs+1; + // start at first element, and to make sure the compiler will not make a calculation each time in the loop + // store a pointer to the current element to modify rather than l_tcp->pocs[i] + l_current_poc = l_tcp->pocs; -void pi_destroy(opj_pi_iterator_t *pi, opj_cp_t *cp, int tileno) { - int compno, pino; - opj_tcp_t *tcp = &cp->tcps[tileno]; - if(pi) { - for (pino = 0; pino < tcp->numpocs + 1; pino++) { - if(pi[pino].comps) { - for (compno = 0; compno < pi->numcomps; compno++) { - opj_pi_comp_t *comp = &pi[pino].comps[compno]; - if(comp->resolutions) { - opj_free(comp->resolutions); + for + (pino = 0; pino < l_poc_bound ; ++pino) + { + l_current_poc->compS = 0; + l_current_poc->compE = p_num_comps;/*p_image->numcomps;*/ + l_current_poc->resS = 0; + l_current_poc->resE = p_max_res; + l_current_poc->layS = 0; + l_current_poc->layE = l_tcp->numlayers; + l_current_poc->prg = l_tcp->prg; + l_current_poc->prcS = 0; + l_current_poc->prcE = p_max_prec; + l_current_poc->txS = p_tx0; + l_current_poc->txE = p_tx1; + l_current_poc->tyS = p_ty0; + l_current_poc->tyE = p_ty1; + l_current_poc->dx = p_dx_min; + l_current_poc->dy = p_dy_min; + ++ l_current_poc; + } +} + +/** + * 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( + 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(pi[pino].comps); + opj_free(l_current_pi->comps); + l_current_pi->comps = 0; } + ++l_current_pi; } - if(pi->include) { - opj_free(pi->include); - } - opj_free(pi); + opj_free(p_pi); } } @@ -726,32 +1655,103 @@ bool pi_next(opj_pi_iterator_t * pi) { return false; } -bool pi_create_encode( opj_pi_iterator_t *pi, opj_cp_t *cp,int tileno, int pino,int tpnum, int tppos, J2K_T2_MODE t2_mode,int cur_totnum_tp){ - char prog[4]; - int i; - int incr_top=1,resetX=0; +OPJ_INT32 pi_check_next_level(OPJ_INT32 pos,opj_cp_t *cp,OPJ_UINT32 tileno, OPJ_UINT32 pino, const OPJ_CHAR *prog) +{ + OPJ_INT32 i,l; opj_tcp_t *tcps =&cp->tcps[tileno]; - opj_poc_t *tcp= &tcps->pocs[pino]; - - pi[pino].first = 1; - pi[pino].poc.prg = tcp->prg; - - switch(tcp->prg){ - case CPRL: strncpy(prog, "CPRL",4); - break; - case LRCP: strncpy(prog, "LRCP",4); - break; - case PCRL: strncpy(prog, "PCRL",4); + opj_poc_t *tcp = &tcps->pocs[pino]; + if(pos>=0){ + for(i=pos;pos>=0;i--){ + switch(prog[i]){ + case 'R': + if(tcp->res_t==tcp->resE){ + l=pi_check_next_level(pos-1,cp,tileno,pino,prog); + if(l==1){ + return 1; + }else{ + return 0; + } + }else{ + return 1; + } break; - case RLCP: strncpy(prog, "RLCP",4); + case 'C': + if(tcp->comp_t==tcp->compE){ + l=pi_check_next_level(pos-1,cp,tileno,pino,prog); + if(l==1){ + return 1; + }else{ + return 0; + } + }else{ + return 1; + } break; - case RPCL: strncpy(prog, "RPCL",4); + case 'L': + if(tcp->lay_t==tcp->layE){ + l=pi_check_next_level(pos-1,cp,tileno,pino,prog); + if(l==1){ + return 1; + }else{ + return 0; + } + }else{ + return 1; + } break; - case PROG_UNKNOWN: - return true; - } + case 'P': + switch(tcp->prg){ + case LRCP||RLCP: + if(tcp->prc_t == tcp->prcE){ + l=pi_check_next_level(i-1,cp,tileno,pino,prog); + if(l==1){ + return 1; + }else{ + return 0; + } + }else{ + return 1; + } + break; + default: + if(tcp->tx0_t == tcp->txE){ + //TY + if(tcp->ty0_t == tcp->tyE){ + l=pi_check_next_level(i-1,cp,tileno,pino,prog); + if(l==1){ + return 1; + }else{ + return 0; + } + }else{ + return 1; + }//TY + }else{ + return 1; + } + break; + }//end case P + }//end switch + }//end for + }//end if + return 0; +} - if(!(cp->tp_on && ((!cp->cinema && (t2_mode == FINAL_PASS)) || cp->cinema))){ + +void pi_create_encode( opj_pi_iterator_t *pi, opj_cp_t *cp,OPJ_UINT32 tileno, OPJ_UINT32 pino,OPJ_UINT32 tpnum, OPJ_INT32 tppos, J2K_T2_MODE t2_mode) +{ + const OPJ_CHAR *prog; + OPJ_INT32 i,l; + OPJ_UINT32 incr_top=1,resetX=0; + opj_tcp_t *tcps =&cp->tcps[tileno]; + opj_poc_t *tcp= &tcps->pocs[pino]; + + prog = j2k_convert_progression_order(tcp->prg); + + pi[pino].first = 1; + pi[pino].poc.prg = tcp->prg; + + if(!(cp->m_specific_param.m_enc.m_tp_on&& ((!cp->m_specific_param.m_enc.m_cinema && (t2_mode == FINAL_PASS)) || cp->m_specific_param.m_enc.m_cinema))){ pi[pino].poc.resno0 = tcp->resS; pi[pino].poc.resno1 = tcp->resE; pi[pino].poc.compno0 = tcp->compS; @@ -765,164 +1765,208 @@ bool pi_create_encode( opj_pi_iterator_t *pi, opj_cp_t *cp,int tileno, int pino, pi[pino].poc.tx1 = tcp->txE; pi[pino].poc.ty1 = tcp->tyE; }else { - if( tpnum < cur_totnum_tp){ - for(i=3;i>=0;i--){ + for(i=tppos+1;i<4;i++){ + switch(prog[i]){ + case 'R': + pi[pino].poc.resno0 = tcp->resS; + pi[pino].poc.resno1 = tcp->resE; + break; + case 'C': + pi[pino].poc.compno0 = tcp->compS; + pi[pino].poc.compno1 = tcp->compE; + break; + case 'L': + pi[pino].poc.layno0 = tcp->layS; + pi[pino].poc.layno1 = tcp->layE; + break; + case 'P': + switch(tcp->prg){ + case LRCP: + case RLCP: + pi[pino].poc.precno0 = tcp->prcS; + pi[pino].poc.precno1 = tcp->prcE; + break; + default: + pi[pino].poc.tx0 = tcp->txS; + pi[pino].poc.ty0 = tcp->tyS; + pi[pino].poc.tx1 = tcp->txE; + pi[pino].poc.ty1 = tcp->tyE; + break; + } + break; + } + } + + if(tpnum==0){ + for(i=tppos;i>=0;i--){ switch(prog[i]){ - case 'C': - if (i > tppos){ - pi[pino].poc.compno0 = tcp->compS; - pi[pino].poc.compno1 = tcp->compE; - }else{ - if (tpnum == 0){ + case 'C': tcp->comp_t = tcp->compS; pi[pino].poc.compno0 = tcp->comp_t; pi[pino].poc.compno1 = tcp->comp_t+1; tcp->comp_t+=1; - }else{ - if (incr_top == 1){ - if(tcp->comp_t ==tcp->compE){ - tcp->comp_t = tcp->compS; - pi[pino].poc.compno0 = tcp->comp_t; - pi[pino].poc.compno1 = tcp->comp_t+1; - tcp->comp_t+=1; - incr_top=1; - }else{ - pi[pino].poc.compno0 = tcp->comp_t; - pi[pino].poc.compno1 = tcp->comp_t+1; - tcp->comp_t+=1; - incr_top=0; - } - }else{ - pi[pino].poc.compno0 = tcp->comp_t-1; - pi[pino].poc.compno1 = tcp->comp_t; - } - } - } - break; - - case 'R': - if (i > tppos){ - pi[pino].poc.resno0 = tcp->resS; - pi[pino].poc.resno1 = tcp->resE; - }else{ - if (tpnum == 0){ + break; + case 'R': tcp->res_t = tcp->resS; pi[pino].poc.resno0 = tcp->res_t; pi[pino].poc.resno1 = tcp->res_t+1; tcp->res_t+=1; - }else{ - if (incr_top == 1){ + break; + case 'L': + tcp->lay_t = tcp->layS; + pi[pino].poc.layno0 = tcp->lay_t; + pi[pino].poc.layno1 = tcp->lay_t+1; + tcp->lay_t+=1; + break; + case 'P': + switch(tcp->prg){ + case LRCP: + case RLCP: + tcp->prc_t = tcp->prcS; + pi[pino].poc.precno0 = tcp->prc_t; + pi[pino].poc.precno1 = tcp->prc_t+1; + tcp->prc_t+=1; + break; + default: + tcp->tx0_t = tcp->txS; + tcp->ty0_t = tcp->tyS; + pi[pino].poc.tx0 = tcp->tx0_t; + pi[pino].poc.tx1 = tcp->tx0_t + tcp->dx - (tcp->tx0_t % tcp->dx); + pi[pino].poc.ty0 = tcp->ty0_t; + pi[pino].poc.ty1 = tcp->ty0_t + tcp->dy - (tcp->ty0_t % tcp->dy); + tcp->tx0_t = pi[pino].poc.tx1; + tcp->ty0_t = pi[pino].poc.ty1; + break; + } + break; + } + } + incr_top=1; + }else{ + for(i=tppos;i>=0;i--){ + switch(prog[i]){ + case 'C': + pi[pino].poc.compno0 = tcp->comp_t-1; + pi[pino].poc.compno1 = tcp->comp_t; + break; + case 'R': + pi[pino].poc.resno0 = tcp->res_t-1; + pi[pino].poc.resno1 = tcp->res_t; + break; + case 'L': + pi[pino].poc.layno0 = tcp->lay_t-1; + pi[pino].poc.layno1 = tcp->lay_t; + break; + case 'P': + switch(tcp->prg){ + case LRCP: + case RLCP: + pi[pino].poc.precno0 = tcp->prc_t-1; + pi[pino].poc.precno1 = tcp->prc_t; + break; + default: + pi[pino].poc.tx0 = tcp->tx0_t - tcp->dx - (tcp->tx0_t % tcp->dx); + pi[pino].poc.tx1 = tcp->tx0_t ; + pi[pino].poc.ty0 = tcp->ty0_t - tcp->dy - (tcp->ty0_t % tcp->dy); + pi[pino].poc.ty1 = tcp->ty0_t ; + break; + } + break; + } + if(incr_top==1){ + switch(prog[i]){ + case 'R': if(tcp->res_t==tcp->resE){ - tcp->res_t = tcp->resS; - pi[pino].poc.resno0 = tcp->res_t; - pi[pino].poc.resno1 = tcp->res_t+1; - tcp->res_t+=1; - incr_top=1; + l=pi_check_next_level(i-1,cp,tileno,pino,prog); + if(l==1){ + tcp->res_t = tcp->resS; + pi[pino].poc.resno0 = tcp->res_t; + pi[pino].poc.resno1 = tcp->res_t+1; + tcp->res_t+=1; + incr_top=1; + }else{ + incr_top=0; + } }else{ pi[pino].poc.resno0 = tcp->res_t; pi[pino].poc.resno1 = tcp->res_t+1; tcp->res_t+=1; incr_top=0; } - }else{ - pi[pino].poc.resno0 = tcp->res_t - 1; - pi[pino].poc.resno1 = tcp->res_t; - } - } - } - break; - - case 'L': - if (i > tppos){ - pi[pino].poc.layno0 = tcp->layS; - pi[pino].poc.layno1 = tcp->layE; - }else{ - if (tpnum == 0){ - tcp->lay_t = tcp->layS; - pi[pino].poc.layno0 = tcp->lay_t; - pi[pino].poc.layno1 = tcp->lay_t+1; - tcp->lay_t+=1; - }else{ - if (incr_top == 1){ + break; + case 'C': + if(tcp->comp_t ==tcp->compE){ + l=pi_check_next_level(i-1,cp,tileno,pino,prog); + if(l==1){ + tcp->comp_t = tcp->compS; + pi[pino].poc.compno0 = tcp->comp_t; + pi[pino].poc.compno1 = tcp->comp_t+1; + tcp->comp_t+=1; + incr_top=1; + }else{ + incr_top=0; + } + }else{ + pi[pino].poc.compno0 = tcp->comp_t; + pi[pino].poc.compno1 = tcp->comp_t+1; + tcp->comp_t+=1; + incr_top=0; + } + break; + case 'L': if(tcp->lay_t == tcp->layE){ - tcp->lay_t = tcp->layS; - pi[pino].poc.layno0 = tcp->lay_t; - pi[pino].poc.layno1 = tcp->lay_t+1; - tcp->lay_t+=1; - incr_top=1; + l=pi_check_next_level(i-1,cp,tileno,pino,prog); + if(l==1){ + tcp->lay_t = tcp->layS; + pi[pino].poc.layno0 = tcp->lay_t; + pi[pino].poc.layno1 = tcp->lay_t+1; + tcp->lay_t+=1; + incr_top=1; + }else{ + incr_top=0; + } }else{ pi[pino].poc.layno0 = tcp->lay_t; pi[pino].poc.layno1 = tcp->lay_t+1; tcp->lay_t+=1; incr_top=0; } - }else{ - pi[pino].poc.layno0 = tcp->lay_t - 1; - pi[pino].poc.layno1 = tcp->lay_t; - } - } - } - break; - - case 'P': - switch(tcp->prg){ - case LRCP: - case RLCP: - if (i > tppos){ - pi[pino].poc.precno0 = tcp->prcS; - pi[pino].poc.precno1 = tcp->prcE; - }else{ - if (tpnum == 0){ - tcp->prc_t = tcp->prcS; - pi[pino].poc.precno0 = tcp->prc_t; - pi[pino].poc.precno1 = tcp->prc_t+1; - tcp->prc_t+=1; - }else{ - if (incr_top == 1){ + break; + case 'P': + switch(tcp->prg){ + case LRCP: + case RLCP: if(tcp->prc_t == tcp->prcE){ - tcp->prc_t = tcp->prcS; - pi[pino].poc.precno0 = tcp->prc_t; - pi[pino].poc.precno1 = tcp->prc_t+1; - tcp->prc_t+=1; - incr_top=1; + l=pi_check_next_level(i-1,cp,tileno,pino,prog); + if(l==1){ + tcp->prc_t = tcp->prcS; + pi[pino].poc.precno0 = tcp->prc_t; + pi[pino].poc.precno1 = tcp->prc_t+1; + tcp->prc_t+=1; + incr_top=1; + }else{ + incr_top=0; + } }else{ pi[pino].poc.precno0 = tcp->prc_t; pi[pino].poc.precno1 = tcp->prc_t+1; tcp->prc_t+=1; incr_top=0; } - }else{ - pi[pino].poc.precno0 = tcp->prc_t - 1; - pi[pino].poc.precno1 = tcp->prc_t; - } - } - } - break; - default: - if (i > tppos){ - pi[pino].poc.tx0 = tcp->txS; - pi[pino].poc.ty0 = tcp->tyS; - pi[pino].poc.tx1 = tcp->txE; - pi[pino].poc.ty1 = tcp->tyE; - }else{ - if (tpnum == 0){ - tcp->tx0_t = tcp->txS; - tcp->ty0_t = tcp->tyS; - pi[pino].poc.tx0 = tcp->tx0_t; - pi[pino].poc.tx1 = tcp->tx0_t + tcp->dx - (tcp->tx0_t % tcp->dx); - pi[pino].poc.ty0 = tcp->ty0_t; - pi[pino].poc.ty1 = tcp->ty0_t + tcp->dy - (tcp->ty0_t % tcp->dy); - tcp->tx0_t = pi[pino].poc.tx1; - tcp->ty0_t = pi[pino].poc.ty1; - }else{ - if (incr_top == 1){ + break; + default: if(tcp->tx0_t >= tcp->txE){ if(tcp->ty0_t >= tcp->tyE){ - tcp->ty0_t = tcp->tyS; - pi[pino].poc.ty0 = tcp->ty0_t; - pi[pino].poc.ty1 = tcp->ty0_t + tcp->dy - (tcp->ty0_t % tcp->dy); - tcp->ty0_t = pi[pino].poc.ty1; - incr_top=1;resetX=1; + l=pi_check_next_level(i-1,cp,tileno,pino,prog); + if(l==1){ + tcp->ty0_t = tcp->tyS; + pi[pino].poc.ty0 = tcp->ty0_t; + pi[pino].poc.ty1 = tcp->ty0_t + tcp->dy - (tcp->ty0_t % tcp->dy); + tcp->ty0_t = pi[pino].poc.ty1; + incr_top=1;resetX=1; + }else{ + incr_top=0;resetX=0; + } }else{ pi[pino].poc.ty0 = tcp->ty0_t; pi[pino].poc.ty1 = tcp->ty0_t + tcp->dy - (tcp->ty0_t % tcp->dy); @@ -939,25 +1983,17 @@ bool pi_create_encode( opj_pi_iterator_t *pi, opj_cp_t *cp,int tileno, int pino, pi[pino].poc.tx0 = tcp->tx0_t; pi[pino].poc.tx1 = tcp->tx0_t + tcp->dx- (tcp->tx0_t % tcp->dx); tcp->tx0_t = pi[pino].poc.tx1; - pi[pino].poc.ty0 = tcp->ty0_t - tcp->dy - (tcp->ty0_t % tcp->dy); - pi[pino].poc.ty1 = tcp->ty0_t ; incr_top=0; } - }else{ - pi[pino].poc.tx0 = tcp->tx0_t - tcp->dx - (tcp->tx0_t % tcp->dx); - pi[pino].poc.tx1 = tcp->tx0_t ; - pi[pino].poc.ty0 = tcp->ty0_t - tcp->dy - (tcp->ty0_t % tcp->dy); - pi[pino].poc.ty1 = tcp->ty0_t ; - } + break; } - } - break; - } - break; - } - } + break; + } + } + } } - } - return false; + } } + + diff --git a/libopenjpeg/pi.h b/libopenjpeg/pi.h index b5e0f6a4..a8abbf74 100644 --- a/libopenjpeg/pi.h +++ b/libopenjpeg/pi.h @@ -5,6 +5,7 @@ * Copyright (c) 2002-2003, Yannick Verschueren * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -39,25 +40,29 @@ The functions in PI.C have for goal to realize a packet iterator that permits to packet following the progression order and change of it. The functions in PI.C are used by some function in T2.C. */ - +#include "openjpeg.h" +#include "t2.h" /** @defgroup PI PI - Implementation of a packet iterator */ /*@{*/ +struct opj_poc; +struct opj_image; +struct opj_cp; /** FIXME: documentation */ typedef struct opj_pi_resolution { - int pdx, pdy; - int pw, ph; + OPJ_UINT32 pdx, pdy; + OPJ_UINT32 pw, ph; } opj_pi_resolution_t; /** FIXME: documentation */ typedef struct opj_pi_comp { - int dx, dy; + OPJ_UINT32 dx, dy; /** number of resolution levels */ - int numresolutions; + OPJ_UINT32 numresolutions; opj_pi_resolution_t *resolutions; } opj_pi_comp_t; @@ -66,50 +71,67 @@ Packet iterator */ typedef struct opj_pi_iterator { /** Enabling Tile part generation*/ - char tp_on; + OPJ_BYTE tp_on; /** precise if the packet has been already used (usefull for progression order change) */ - short int *include; + OPJ_INT16 *include; /** layer step used to localize the packet in the include vector */ - int step_l; + OPJ_UINT32 step_l; /** resolution step used to localize the packet in the include vector */ - int step_r; + OPJ_UINT32 step_r; /** component step used to localize the packet in the include vector */ - int step_c; + OPJ_UINT32 step_c; /** precinct step used to localize the packet in the include vector */ - int step_p; + OPJ_UINT32 step_p; /** component that identify the packet */ - int compno; + OPJ_UINT32 compno; /** resolution that identify the packet */ - int resno; + OPJ_UINT32 resno; /** precinct that identify the packet */ - int precno; + OPJ_UINT32 precno; /** layer that identify the packet */ - int layno; - /** 0 if the first packet */ - int first; + OPJ_UINT32 layno; /** progression order change information */ - opj_poc_t poc; + struct opj_poc poc; /** number of components in the image */ - int numcomps; + OPJ_UINT32 numcomps; /** Components*/ opj_pi_comp_t *comps; - int tx0, ty0, tx1, ty1; - int x, y, dx, dy; + OPJ_INT32 tx0, ty0, tx1, ty1; + OPJ_INT32 x, y; + OPJ_UINT32 dx, dy; + /** 0 if the first packet */ + OPJ_UINT32 first : 1; } opj_pi_iterator_t; /** @name Exported functions */ /*@{*/ /* ----------------------------------------------------------------------- */ /** -Create a packet iterator for Encoder -@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 -@param t2_mode If == 0 In Threshold calculation ,If == 1 Final pass -@return Returns a packet iterator that points to the first packet of the tile -@see pi_destroy + * Creates a packet iterator for encoding. + * + * @param p_image the image being encoded. + * @param p_cp the coding parameters. + * @param p_tile_no index of the tile being encoded. + * @param p_t2_mode the type of pass for generating the packet iterator + * @return a list of packet iterator that points to the first packet of the tile (not true). */ -opj_pi_iterator_t *pi_initialise_encode(opj_image_t *image, opj_cp_t *cp, int tileno,J2K_T2_MODE t2_mode); +opj_pi_iterator_t *pi_initialise_encode(const struct opj_image *image,struct opj_cp *cp, OPJ_UINT32 tileno,J2K_T2_MODE t2_mode); + +/** + * Updates the encoding parameters of the codec. + * + * @param p_image the image being encoded. + * @param p_cp the coding parameters. + * @param p_tile_no index of the tile being encoded. +*/ +void pi_update_encoding_parameters( + const struct opj_image *p_image, + struct opj_cp *p_cp, + OPJ_UINT32 p_tile_no + ); + + + /** Modify the packet iterator for enabling tile part generation @param pi Handle to the packet iterator generated in pi_initialise_encode @@ -117,10 +139,10 @@ Modify the packet iterator for enabling tile part generation @param tileno Number that identifies the tile for which to list the packets @param tpnum Tile part number of the current tile @param tppos The position of the tile part flag in the progression order -@param cur_totnum_tp The total number of tile parts in the current tile -@return Returns true if an error is detected */ -bool pi_create_encode(opj_pi_iterator_t *pi, opj_cp_t *cp,int tileno, int pino,int tpnum, int tppos, J2K_T2_MODE t2_mode,int cur_totnum_tp); +void pi_create_encode( opj_pi_iterator_t *pi, struct opj_cp *cp,OPJ_UINT32 tileno, OPJ_UINT32 pino,OPJ_UINT32 tpnum, OPJ_INT32 tppos, J2K_T2_MODE t2_mode); + + /** Create a packet iterator for Decoder @param image Raw image for which the packets will be listed @@ -129,16 +151,19 @@ Create a packet iterator for Decoder @return Returns a packet iterator that points to the first packet of the tile @see pi_destroy */ -opj_pi_iterator_t *pi_create_decode(opj_image_t * image, opj_cp_t * cp, int tileno); +opj_pi_iterator_t *pi_create_decode(struct opj_image * image, struct opj_cp * cp, OPJ_UINT32 tileno); + + /** -Destroy a packet iterator -@param pi Previously created packet iterator -@param cp Coding parameters -@param tileno Number that identifies the tile for which the packets were listed -@see pi_create -*/ -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( + opj_pi_iterator_t *p_pi, + OPJ_UINT32 p_nb_elements); /** Modify the packet iterator to point to the next packet @@ -146,6 +171,8 @@ Modify the packet iterator to point to the next packet @return Returns false if pi pointed to the last packet or else returns true */ bool pi_next(opj_pi_iterator_t * pi); + + /* ----------------------------------------------------------------------- */ /*@}*/ diff --git a/libopenjpeg/profile.c b/libopenjpeg/profile.c new file mode 100644 index 00000000..d153b278 --- /dev/null +++ b/libopenjpeg/profile.c @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Adapted from Herb Marselas +"Profiling, Data Analysis, Scalability, and Magic Numbers: Meeting the Minimum System Requirements for AGE OF EMPIRES 2: THE AGE OF KINGS" +Game Developer magazine +June, 2000 issue. +*/ + +#include "profile.h" +#include <string.h> +#include <stdio.h> +#include <time.h> +//============================================================================== +static OPJ_PROFILE_LIST group_list [PGROUP_LASTGROUP]; + +//============================================================================== +static void GetTimeStamp(OPJ_UINT32 *pdwtime); + +//============================================================================== +#define SetMajorSection(entry, major) \ + { group_list[ entry ].section = entry ; \ + group_list[ entry ].sectionName = #major ; } + +//============================================================================== +void _ProfInit(void) +{ + // clear everything out + memset(group_list, 0, sizeof(group_list)); + + // set groups and parents for timing + SetMajorSection(PGROUP_DWT,PGROUP_DWT); + SetMajorSection(PGROUP_T1, PGROUP_T1); + SetMajorSection(PGROUP_T2, PGROUP_T2); +} // ProfInit + +//============================================================================== +void _ProfStart (OPJ_PROFILE_GROUP group) +{ + // make sure this hasn't been incorrectly started twice + if (group_list[group].start) + { + return; + } + + // get the start time + GetTimeStamp(&(group_list[group].start)); + +} // _ProfStart + +//============================================================================== +void _ProfStop(OPJ_PROFILE_GROUP group) +{ + // make sure we called start first + if (!group_list[group].start) + { + return; + } + + // get ending time + GetTimeStamp(&(group_list[group].end)); + + // calculate this latest elapsed interval + group_list[group].total_time += group_list[group].end - group_list[group].start; + + // reset starting time + group_list[group].start = 0; + + // incr the number of calls made + ++group_list[group].totalCalls; + +} // _ProfStop + +//============================================================================== +#define proftracef(id,totalTime) \ + fprintf(p, #id "\t%u\t\t%6.6f\t\t%12.6f\t%2.2f%%\n", \ + group_list[ id ].totalCalls, \ + (OPJ_FLOAT64) group_list[ id ].total_time / CLOCKS_PER_SEC, \ + ((OPJ_FLOAT64) group_list[ id ].total_time / (group_list[ id ].totalCalls ? group_list[ id ].totalCalls : 1)), \ + ((OPJ_FLOAT64) group_list[ id ].total_time / totalTime * 100)) + +#define proftracep(id,totalTime) \ + printf(#id "\t%u\t\t%6.6f\t\t%12.6f\t%2.2f%%\n", \ + group_list[ id ].totalCalls, \ + (OPJ_FLOAT64) group_list[ id ].total_time / CLOCKS_PER_SEC, \ + ((OPJ_FLOAT64) group_list[ id ].total_time / (group_list[ id ].totalCalls ? group_list[ id ].totalCalls : 1)), \ + ((OPJ_FLOAT64) group_list[ id ].total_time / totalTime * 100)) + +//============================================================================== +void _ProfSave(const OPJ_CHAR * pFileName) +{ + FILE *p = fopen(pFileName, "wt"); + OPJ_FLOAT64 totalTime = 0.; + OPJ_UINT32 i; + + if (!p) + { + return; + } + + for + (i=0;i<PGROUP_LASTGROUP;++i) + { + totalTime += group_list[i].total_time; + } + + fputs("\n\nProfile Data:\n", p); + fputs("description\tnb calls\ttotal time (sec)\ttime per call\t%% of section\n", p); + + proftracef(PGROUP_DWT,totalTime); + proftracef(PGROUP_T1,totalTime); + proftracef(PGROUP_T2,totalTime); + + fputs("=== end of profile list ===\n\n", p); + + fclose(p); + +} // _ProfSave + +//============================================================================== +void _ProfPrint(void) +{ + OPJ_FLOAT64 totalTime = 0.; + OPJ_UINT32 i; + + for + (i=0;i<PGROUP_LASTGROUP;++i) + { + totalTime += group_list[i].total_time; + } + + printf("\n\nProfile Data:\n"); + printf("description\tnb calls\ttotal time (sec)\ttime per call\t%% of section\n"); + + proftracep(PGROUP_RATE, totalTime); + proftracep(PGROUP_DC_SHIFT, totalTime); + proftracep(PGROUP_MCT, totalTime); + proftracep(PGROUP_DWT, totalTime); + proftracep(PGROUP_T1, totalTime); + proftracep(PGROUP_T2, totalTime); + + printf("\nTotal time: %6.3f second(s)\n", totalTime / CLOCKS_PER_SEC); + + printf("=== end of profile list ===\n\n"); + +} // _ProfPrint + +//============================================================================== +static void GetTimeStamp(unsigned *time) +{ + *time = clock(); + +} // GetTimeStamp diff --git a/libopenjpeg/profile.h b/libopenjpeg/profile.h new file mode 100644 index 00000000..dd9e12f1 --- /dev/null +++ b/libopenjpeg/profile.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Adapted from Herb Marselas +"Profiling, Data Analysis, Scalability, and Magic Numbers: Meeting the Minimum System Requirements for AGE OF EMPIRES 2: THE AGE OF KINGS" +Game Developer magazine +June, 2000 issue. +*/ + + +#ifndef __PROFILE_H +#define __PROFILE_H + +#include "openjpeg.h" +//============================================================================== +typedef enum +{ + PGROUP_RATE, + PGROUP_DC_SHIFT, + PGROUP_MCT, + PGROUP_DWT, + PGROUP_T1, + PGROUP_T2, + PGROUP_LASTGROUP +} OPJ_PROFILE_GROUP; + +//============================================================================== +typedef struct PROFILELIST +{ + OPJ_UINT32 start; + OPJ_UINT32 end; + OPJ_UINT32 total_time; + OPJ_UINT32 totalCalls; + OPJ_PROFILE_GROUP section; + const OPJ_CHAR *sectionName; // string name of the profile group +} OPJ_PROFILE_LIST; + +//============================================================================== +void _ProfStart(OPJ_PROFILE_GROUP group); +void _ProfStop (OPJ_PROFILE_GROUP group); + +//============================================================================== +//============================================================================== +#ifdef _PROFILE +#define PROFINIT() _ProfInit(); +#define PROFSTART (group) _ProfStart (group); +#define PROFSTOP (group) _ProfStop (group); +#define PROFSAVE(file) _ProfSave(file); +#define PROFPRINT() _ProfPrint(); +#else +#define PROFINIT() +#define PROFSTART(group) +#define PROFSTOP (group) +#define PROFSAVE(file) +#define PROFPRINT() +#endif // !_PROFILE + +//============================================================================== +#endif // __PROFILE_H diff --git a/libopenjpeg/raw.c b/libopenjpeg/raw.c index 3d231bfd..d42528d2 100644 --- a/libopenjpeg/raw.c +++ b/libopenjpeg/raw.c @@ -3,6 +3,7 @@ * Copyright (c) 2002-2007, Professor Benoit Macq * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,7 +28,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "opj_includes.h" +#include "raw.h" +#include "opj_malloc.h" /* ========================================================== @@ -53,11 +55,11 @@ void raw_destroy(opj_raw_t *raw) { } } -int raw_numbytes(opj_raw_t *raw) { +OPJ_UINT32 raw_numbytes(opj_raw_t *raw) { return raw->bp - raw->start; } -void raw_init_dec(opj_raw_t *raw, unsigned char *bp, int len) { +void raw_init_dec(opj_raw_t *raw, OPJ_BYTE *bp, OPJ_UINT32 len) { raw->start = bp; raw->lenmax = len; raw->len = 0; @@ -65,8 +67,8 @@ void raw_init_dec(opj_raw_t *raw, unsigned char *bp, int len) { raw->ct = 0; } -int raw_decode(opj_raw_t *raw) { - int d; +OPJ_UINT32 raw_decode(opj_raw_t *raw) { + OPJ_UINT32 d; if (raw->ct == 0) { raw->ct = 8; if (raw->len == raw->lenmax) { diff --git a/libopenjpeg/raw.h b/libopenjpeg/raw.h index 3c4b372f..5d23f7a1 100644 --- a/libopenjpeg/raw.h +++ b/libopenjpeg/raw.h @@ -3,6 +3,7 @@ * Copyright (c) 2002-2007, Professor Benoit Macq * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -36,7 +37,7 @@ The functions in RAW.C have for goal to realize the operation of raw encoding linked with the corresponding mode switch. */ - +#include "openjpeg.h" /** @defgroup RAW RAW - Implementation of operations for raw encoding */ /*@{*/ @@ -45,17 +46,17 @@ RAW encoding operations */ typedef struct opj_raw { /** temporary buffer where bits are coded or decoded */ - unsigned char c; + OPJ_BYTE c; /** number of bits already read or free to write */ - unsigned int ct; + OPJ_UINT32 ct; /** maximum length to decode */ - unsigned int lenmax; + OPJ_UINT32 lenmax; /** length decoded */ - unsigned int len; + OPJ_UINT32 len; /** pointer to the current position in the buffer */ - unsigned char *bp; + OPJ_BYTE *bp; /** pointer to the start of the buffer */ - unsigned char *start; + OPJ_BYTE *start; /** pointer to the end of the buffer */ unsigned char *end; } opj_raw_t; @@ -78,20 +79,20 @@ Return the number of bytes written/read since initialisation @param raw RAW handle to destroy @return Returns the number of bytes already encoded */ -int raw_numbytes(opj_raw_t *raw); +OPJ_UINT32 raw_numbytes(opj_raw_t *raw); /** Initialize the decoder @param raw RAW handle @param bp Pointer to the start of the buffer from which the bytes will be read @param len Length of the input buffer */ -void raw_init_dec(opj_raw_t *raw, unsigned char *bp, int len); +void raw_init_dec(opj_raw_t *raw, OPJ_BYTE *bp, OPJ_UINT32 len); /** Decode a symbol using raw-decoder. Cfr p.506 TAUBMAN @param raw RAW handle @return Returns the decoded symbol (0 or 1) */ -int raw_decode(opj_raw_t *raw); +OPJ_UINT32 raw_decode(opj_raw_t *raw); /* ----------------------------------------------------------------------- */ /*@}*/ diff --git a/libopenjpeg/t1.c b/libopenjpeg/t1.c index ad1c6a83..139ff48e 100644 --- a/libopenjpeg/t1.c +++ b/libopenjpeg/t1.c @@ -6,6 +6,7 @@ * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe * Copyright (c) 2005, Herve Drolon, FreeImage Team * Copyright (c) 2007, Callum Lerwick <seg@haxxed.com> + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,155 +31,165 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "opj_includes.h" +#include "t1.h" #include "t1_luts.h" - +#include "opj_includes.h" +#include "j2k.h" +#include "tcd.h" +#include "mqc.h" +#include "raw.h" +#include "opj_malloc.h" +#include "int.h" +#include "dwt.h" +#include "fix.h" /** @defgroup T1 T1 - Implementation of the tier-1 coding */ /*@{*/ /** @name Local static functions */ /*@{*/ -static INLINE char t1_getctxno_zc(int f, int orient); -static char t1_getctxno_sc(int f); -static INLINE int t1_getctxno_mag(int f); -static char t1_getspb(int f); -static short t1_getnmsedec_sig(int x, int bitpos); -static short t1_getnmsedec_ref(int x, int bitpos); -static void t1_updateflags(flag_t *flagsp, int s, int stride); +static INLINE OPJ_BYTE t1_getctxno_zc(OPJ_UINT32 f, OPJ_UINT32 orient); +static OPJ_BYTE t1_getctxno_sc(OPJ_UINT32 f); +static INLINE OPJ_UINT32 t1_getctxno_mag(OPJ_UINT32 f); +static OPJ_BYTE t1_getspb(OPJ_UINT32 f); +static OPJ_INT16 t1_getnmsedec_sig(OPJ_UINT32 x, OPJ_UINT32 bitpos); +static OPJ_INT16 t1_getnmsedec_ref(OPJ_UINT32 x, OPJ_UINT32 bitpos); +static void t1_updateflags(flag_t *flagsp, OPJ_UINT32 s, OPJ_UINT32 stride); /** Encode significant pass */ static void t1_enc_sigpass_step( opj_t1_t *t1, flag_t *flagsp, - int *datap, - int orient, - int bpno, - int one, - int *nmsedec, - char type, - int vsc); + OPJ_INT32 *datap, + OPJ_UINT32 orient, + OPJ_INT32 bpno, + OPJ_INT32 one, + OPJ_INT32 *nmsedec, + OPJ_BYTE type, + OPJ_UINT32 vsc); /** Decode significant pass */ static void t1_dec_sigpass_step( opj_t1_t *t1, flag_t *flagsp, - int *datap, - int orient, - int oneplushalf, - char type, - int vsc); + OPJ_INT32 *datap, + OPJ_UINT32 orient, + OPJ_INT32 oneplushalf, + OPJ_BYTE type, + OPJ_UINT32 vsc); /** Encode significant pass */ static void t1_enc_sigpass( opj_t1_t *t1, - int bpno, - int orient, - int *nmsedec, - char type, - int cblksty); + OPJ_INT32 bpno, + OPJ_UINT32 orient, + OPJ_INT32 *nmsedec, + OPJ_BYTE type, + OPJ_UINT32 cblksty); /** Decode significant pass */ static void t1_dec_sigpass( opj_t1_t *t1, - int bpno, - int orient, - char type, - int cblksty); + OPJ_INT32 bpno, + OPJ_UINT32 orient, + OPJ_BYTE type, + OPJ_UINT32 cblksty); /** Encode refinement pass */ static void t1_enc_refpass_step( opj_t1_t *t1, flag_t *flagsp, - int *datap, - int bpno, - int one, - int *nmsedec, - char type, - int vsc); + OPJ_INT32 *datap, + OPJ_INT32 bpno, + OPJ_INT32 one, + OPJ_INT32 *nmsedec, + OPJ_BYTE type, + OPJ_UINT32 vsc); /** Decode refinement pass */ static void t1_dec_refpass_step( opj_t1_t *t1, flag_t *flagsp, - int *datap, - int poshalf, - int neghalf, - char type, - int vsc); + OPJ_INT32 *datap, + OPJ_INT32 poshalf, + OPJ_INT32 neghalf, + OPJ_BYTE type, + OPJ_UINT32 vsc); /** Encode refinement pass */ static void t1_enc_refpass( opj_t1_t *t1, - int bpno, - int *nmsedec, - char type, - int cblksty); + OPJ_INT32 bpno, + OPJ_INT32 *nmsedec, + OPJ_BYTE type, + OPJ_UINT32 cblksty); /** Decode refinement pass */ static void t1_dec_refpass( opj_t1_t *t1, - int bpno, - char type, - int cblksty); + OPJ_INT32 bpno, + OPJ_BYTE type, + OPJ_UINT32 cblksty); /** Encode clean-up pass */ static void t1_enc_clnpass_step( opj_t1_t *t1, flag_t *flagsp, - int *datap, - int orient, - int bpno, - int one, - int *nmsedec, - int partial, - int vsc); + OPJ_INT32 *datap, + OPJ_UINT32 orient, + OPJ_INT32 bpno, + OPJ_INT32 one, + OPJ_INT32 *nmsedec, + OPJ_UINT32 partial, + OPJ_UINT32 vsc); /** Decode clean-up pass */ static void t1_dec_clnpass_step( opj_t1_t *t1, flag_t *flagsp, - int *datap, - int orient, - int oneplushalf, - int partial, - int vsc); + OPJ_INT32 *datap, + OPJ_UINT32 orient, + OPJ_INT32 oneplushalf, + OPJ_UINT32 partial, + OPJ_UINT32 vsc); /** Encode clean-up pass */ static void t1_enc_clnpass( opj_t1_t *t1, - int bpno, - int orient, - int *nmsedec, - int cblksty); + OPJ_INT32 bpno, + OPJ_UINT32 orient, + OPJ_INT32 *nmsedec, + OPJ_UINT32 cblksty); /** Decode clean-up pass */ static void t1_dec_clnpass( opj_t1_t *t1, - int bpno, - int orient, - int cblksty); -static double t1_getwmsedec( - int nmsedec, - int compno, - int level, - int orient, - int bpno, - int qmfbid, - double stepsize, - int numcomps); + OPJ_INT32 bpno, + OPJ_UINT32 orient, + OPJ_UINT32 cblksty); + +static OPJ_FLOAT64 t1_getwmsedec( + OPJ_INT32 nmsedec, + OPJ_UINT32 compno, + OPJ_UINT32 level, + OPJ_UINT32 orient, + OPJ_INT32 bpno, + OPJ_UINT32 qmfbid, + OPJ_FLOAT64 stepsize, + OPJ_UINT32 numcomps, + const OPJ_FLOAT64 * mct_norms); /** Encode 1 code-block @param t1 T1 handle @@ -195,14 +206,15 @@ Encode 1 code-block static void t1_encode_cblk( opj_t1_t *t1, opj_tcd_cblk_enc_t* cblk, - int orient, - int compno, - int level, - int qmfbid, - double stepsize, - int cblksty, - int numcomps, - opj_tcd_tile_t * tile); + OPJ_UINT32 orient, + OPJ_UINT32 compno, + OPJ_UINT32 level, + OPJ_UINT32 qmfbid, + OPJ_FLOAT64 stepsize, + OPJ_UINT32 cblksty, + OPJ_UINT32 numcomps, + opj_tcd_tile_t * tile, + const OPJ_FLOAT64 * mct_norms); /** Decode 1 code-block @param t1 T1 handle @@ -214,9 +226,9 @@ Decode 1 code-block static void t1_decode_cblk( opj_t1_t *t1, opj_tcd_cblk_dec_t* cblk, - int orient, - int roishift, - int cblksty); + OPJ_UINT32 orient, + OPJ_UINT32 roishift, + OPJ_UINT32 cblksty); /*@}*/ @@ -224,25 +236,26 @@ static void t1_decode_cblk( /* ----------------------------------------------------------------------- */ -static char t1_getctxno_zc(int f, int orient) { +static OPJ_BYTE t1_getctxno_zc(OPJ_UINT32 f, OPJ_UINT32 orient) { return lut_ctxno_zc[(orient << 8) | (f & T1_SIG_OTH)]; } -static char t1_getctxno_sc(int f) { +static OPJ_BYTE t1_getctxno_sc(OPJ_UINT32 f) { return lut_ctxno_sc[(f & (T1_SIG_PRIM | T1_SGN)) >> 4]; } -static int t1_getctxno_mag(int f) { - int tmp1 = (f & T1_SIG_OTH) ? T1_CTXNO_MAG + 1 : T1_CTXNO_MAG; - int tmp2 = (f & T1_REFINE) ? T1_CTXNO_MAG + 2 : tmp1; +static OPJ_UINT32 t1_getctxno_mag(OPJ_UINT32 f) { + OPJ_UINT32 tmp1 = (f & T1_SIG_OTH) ? T1_CTXNO_MAG + 1 : T1_CTXNO_MAG; + OPJ_UINT32 tmp2 = (f & T1_REFINE) ? T1_CTXNO_MAG + 2 : tmp1; return (tmp2); } -static char t1_getspb(int f) { +static OPJ_BYTE t1_getspb(OPJ_UINT32 f) { return lut_spb[(f & (T1_SIG_PRIM | T1_SGN)) >> 4]; } -static short t1_getnmsedec_sig(int x, int bitpos) { +static OPJ_INT16 t1_getnmsedec_sig(OPJ_UINT32 x, OPJ_UINT32 bitpos) +{ if (bitpos > T1_NMSEDEC_FRACBITS) { return lut_nmsedec_sig[(x >> (bitpos - T1_NMSEDEC_FRACBITS)) & ((1 << T1_NMSEDEC_BITS) - 1)]; } @@ -250,7 +263,7 @@ static short t1_getnmsedec_sig(int x, int bitpos) { return lut_nmsedec_sig0[x & ((1 << T1_NMSEDEC_BITS) - 1)]; } -static short t1_getnmsedec_ref(int x, int bitpos) { +static OPJ_INT16 t1_getnmsedec_ref(OPJ_UINT32 x, OPJ_UINT32 bitpos) { if (bitpos > T1_NMSEDEC_FRACBITS) { return lut_nmsedec_ref[(x >> (bitpos - T1_NMSEDEC_FRACBITS)) & ((1 << T1_NMSEDEC_BITS) - 1)]; } @@ -258,7 +271,7 @@ static short t1_getnmsedec_ref(int x, int bitpos) { return lut_nmsedec_ref0[x & ((1 << T1_NMSEDEC_BITS) - 1)]; } -static void t1_updateflags(flag_t *flagsp, int s, int stride) { +static void t1_updateflags(flag_t *flagsp, OPJ_UINT32 s, OPJ_UINT32 stride) { flag_t *np = flagsp - stride; flag_t *sp = flagsp + stride; @@ -285,15 +298,16 @@ static void t1_updateflags(flag_t *flagsp, int s, int stride) { static void t1_enc_sigpass_step( opj_t1_t *t1, flag_t *flagsp, - int *datap, - int orient, - int bpno, - int one, - int *nmsedec, - char type, - int vsc) + OPJ_INT32 *datap, + OPJ_UINT32 orient, + OPJ_INT32 bpno, + OPJ_INT32 one, + OPJ_INT32 *nmsedec, + OPJ_BYTE type, + OPJ_UINT32 vsc) { - int v, flag; + OPJ_INT32 v; + OPJ_UINT32 flag; opj_mqc_t *mqc = t1->mqc; /* MQC component */ @@ -324,13 +338,13 @@ static void t1_enc_sigpass_step( static void t1_dec_sigpass_step( opj_t1_t *t1, flag_t *flagsp, - int *datap, - int orient, - int oneplushalf, - char type, - int vsc) + OPJ_INT32 *datap, + OPJ_UINT32 orient, + OPJ_INT32 oneplushalf, + OPJ_BYTE type, + OPJ_UINT32 vsc) { - int v, flag; + OPJ_UINT32 v, flag; opj_raw_t *raw = t1->raw; /* RAW component */ opj_mqc_t *mqc = t1->mqc; /* MQC component */ @@ -358,13 +372,15 @@ static void t1_dec_sigpass_step( static void t1_enc_sigpass( opj_t1_t *t1, - int bpno, - int orient, - int *nmsedec, - char type, - int cblksty) + OPJ_INT32 bpno, + OPJ_UINT32 orient, + OPJ_INT32 *nmsedec, + OPJ_BYTE type, + OPJ_UINT32 cblksty) { - int i, j, k, one, vsc; + OPJ_UINT32 i, j, k, vsc; + OPJ_INT32 one; + *nmsedec = 0; one = 1 << (bpno + T1_NMSEDEC_FRACBITS); for (k = 0; k < t1->h; k += 4) { @@ -388,12 +404,13 @@ static void t1_enc_sigpass( static void t1_dec_sigpass( opj_t1_t *t1, - int bpno, - int orient, - char type, - int cblksty) + OPJ_INT32 bpno, + OPJ_UINT32 orient, + OPJ_BYTE type, + OPJ_UINT32 cblksty) { - int i, j, k, one, half, oneplushalf, vsc; + OPJ_UINT32 i, j, k, vsc; + OPJ_INT32 one, half, oneplushalf; one = 1 << bpno; half = one >> 1; oneplushalf = one | half; @@ -417,14 +434,15 @@ static void t1_dec_sigpass( static void t1_enc_refpass_step( opj_t1_t *t1, flag_t *flagsp, - int *datap, - int bpno, - int one, - int *nmsedec, - char type, - int vsc) + OPJ_INT32 *datap, + OPJ_INT32 bpno, + OPJ_INT32 one, + OPJ_INT32 *nmsedec, + OPJ_BYTE type, + OPJ_UINT32 vsc) { - int v, flag; + OPJ_INT32 v; + OPJ_UINT32 flag; opj_mqc_t *mqc = t1->mqc; /* MQC component */ @@ -445,13 +463,14 @@ static void t1_enc_refpass_step( static void t1_dec_refpass_step( opj_t1_t *t1, flag_t *flagsp, - int *datap, - int poshalf, - int neghalf, - char type, - int vsc) + OPJ_INT32 *datap, + OPJ_INT32 poshalf, + OPJ_INT32 neghalf, + OPJ_BYTE type, + OPJ_UINT32 vsc) { - int v, t, flag; + OPJ_INT32 t; + OPJ_UINT32 v,flag; opj_mqc_t *mqc = t1->mqc; /* MQC component */ opj_raw_t *raw = t1->raw; /* RAW component */ @@ -472,12 +491,14 @@ static void t1_dec_refpass_step( static void t1_enc_refpass( opj_t1_t *t1, - int bpno, - int *nmsedec, - char type, - int cblksty) + OPJ_INT32 bpno, + OPJ_INT32 *nmsedec, + OPJ_BYTE type, + OPJ_UINT32 cblksty) { - int i, j, k, one, vsc; + OPJ_UINT32 i, j, k, vsc; + OPJ_INT32 one; + *nmsedec = 0; one = 1 << (bpno + T1_NMSEDEC_FRACBITS); for (k = 0; k < t1->h; k += 4) { @@ -500,12 +521,13 @@ static void t1_enc_refpass( static void t1_dec_refpass( opj_t1_t *t1, - int bpno, - char type, - int cblksty) + OPJ_INT32 bpno, + OPJ_BYTE type, + OPJ_UINT32 cblksty) { - int i, j, k, one, poshalf, neghalf; - int vsc; + OPJ_UINT32 i, j, k; + OPJ_INT32 one, poshalf, neghalf; + OPJ_UINT32 vsc; one = 1 << bpno; poshalf = one >> 1; neghalf = bpno > 0 ? -poshalf : -1; @@ -529,15 +551,16 @@ static void t1_dec_refpass( static void t1_enc_clnpass_step( opj_t1_t *t1, flag_t *flagsp, - int *datap, - int orient, - int bpno, - int one, - int *nmsedec, - int partial, - int vsc) + OPJ_INT32 *datap, + OPJ_UINT32 orient, + OPJ_INT32 bpno, + OPJ_INT32 one, + OPJ_INT32 *nmsedec, + OPJ_UINT32 partial, + OPJ_UINT32 vsc) { - int v, flag; + OPJ_INT32 v; + OPJ_UINT32 flag; opj_mqc_t *mqc = t1->mqc; /* MQC component */ @@ -564,13 +587,14 @@ LABEL_PARTIAL: static void t1_dec_clnpass_step( opj_t1_t *t1, flag_t *flagsp, - int *datap, - int orient, - int oneplushalf, - int partial, - int vsc) + OPJ_INT32 *datap, + OPJ_UINT32 orient, + OPJ_INT32 oneplushalf, + OPJ_UINT32 partial, + OPJ_UINT32 vsc) { - int v, flag; + OPJ_INT32 v; + OPJ_UINT32 flag; opj_mqc_t *mqc = t1->mqc; /* MQC component */ @@ -593,12 +617,14 @@ LABEL_PARTIAL: static void t1_enc_clnpass( opj_t1_t *t1, - int bpno, - int orient, - int *nmsedec, - int cblksty) + OPJ_INT32 bpno, + OPJ_UINT32 orient, + OPJ_INT32 *nmsedec, + OPJ_UINT32 cblksty) { - int i, j, k, one, agg, runlen, vsc; + OPJ_UINT32 i, j, k; + OPJ_INT32 one; + OPJ_UINT32 agg, runlen, vsc; opj_mqc_t *mqc = t1->mqc; /* MQC component */ @@ -657,12 +683,14 @@ static void t1_enc_clnpass( static void t1_dec_clnpass( opj_t1_t *t1, - int bpno, - int orient, - int cblksty) + OPJ_INT32 bpno, + OPJ_UINT32 orient, + OPJ_UINT32 cblksty) { - int i, j, k, one, half, oneplushalf, agg, runlen, vsc; - int segsym = cblksty & J2K_CCP_CBLKSTY_SEGSYM; + OPJ_UINT32 i, j, k, one; + OPJ_INT32 half, oneplushalf; + OPJ_UINT32 agg, runlen, vsc; + OPJ_UINT32 segsym = cblksty & J2K_CCP_CBLKSTY_SEGSYM; opj_mqc_t *mqc = t1->mqc; /* MQC component */ @@ -712,7 +740,7 @@ static void t1_dec_clnpass( } } if (segsym) { - int v = 0; + OPJ_UINT32 v = 0; mqc_setcurctx(mqc, T1_CTXNO_UNI); v = mqc_decode(mqc); v = (v << 1) | mqc_decode(mqc); @@ -728,47 +756,51 @@ static void t1_dec_clnpass( /** mod fixed_quality */ -static double t1_getwmsedec( - int nmsedec, - int compno, - int level, - int orient, - int bpno, - int qmfbid, - double stepsize, - int numcomps) +static OPJ_FLOAT64 t1_getwmsedec( + OPJ_INT32 nmsedec, + OPJ_UINT32 compno, + OPJ_UINT32 level, + OPJ_UINT32 orient, + OPJ_INT32 bpno, + OPJ_UINT32 qmfbid, + OPJ_FLOAT64 stepsize, + OPJ_UINT32 numcomps, + const OPJ_FLOAT64 * mct_norms) { - double w1, w2, wmsedec; - if (qmfbid == 1) { - w1 = (numcomps > 1) ? mct_getnorm(compno) : 1.0; + OPJ_FLOAT64 w1 = 1, w2, wmsedec; + if + (mct_norms) + { + w1 = mct_norms[compno]; + } + if (qmfbid == 1) + { w2 = dwt_getnorm(level, orient); } else { /* if (qmfbid == 0) */ - w1 = (numcomps > 1) ? mct_getnorm_real(compno) : 1.0; w2 = dwt_getnorm_real(level, orient); } wmsedec = w1 * w2 * stepsize * (1 << bpno); wmsedec *= wmsedec * nmsedec / 8192.0; - return wmsedec; } static bool allocate_buffers( opj_t1_t *t1, - int w, - int h) + OPJ_UINT32 w, + OPJ_UINT32 h) { - int datasize=w * h; - int flagssize; + OPJ_UINT32 datasize=w * h; + OPJ_UINT32 flagssize; if(datasize > t1->datasize){ opj_aligned_free(t1->data); - t1->data = (int*) opj_aligned_malloc(datasize * sizeof(int)); + t1->data = (OPJ_INT32*) opj_aligned_malloc(datasize * sizeof(OPJ_INT32)); if(!t1->data){ return false; } t1->datasize=datasize; } - memset(t1->data,0,datasize * sizeof(int)); + memset(t1->data,0,datasize * sizeof(OPJ_INT32)); t1->flags_stride=w+2; flagssize=t1->flags_stride * (h+2); @@ -793,28 +825,32 @@ static bool allocate_buffers( static void t1_encode_cblk( opj_t1_t *t1, opj_tcd_cblk_enc_t* cblk, - int orient, - int compno, - int level, - int qmfbid, - double stepsize, - int cblksty, - int numcomps, - opj_tcd_tile_t * tile) + OPJ_UINT32 orient, + OPJ_UINT32 compno, + OPJ_UINT32 level, + OPJ_UINT32 qmfbid, + OPJ_FLOAT64 stepsize, + OPJ_UINT32 cblksty, + OPJ_UINT32 numcomps, + opj_tcd_tile_t * tile, + const OPJ_FLOAT64 * mct_norms) { - double cumwmsedec = 0.0; + OPJ_FLOAT64 cumwmsedec = 0.0; opj_mqc_t *mqc = t1->mqc; /* MQC component */ - int passno, bpno, passtype; - int nmsedec = 0; - int i, max; - char type = T1_TYPE_MQ; - double tempwmsedec; + OPJ_UINT32 passno; + OPJ_INT32 bpno; + OPJ_UINT32 passtype; + OPJ_INT32 nmsedec = 0; + OPJ_INT32 max; + OPJ_UINT32 i; + OPJ_BYTE type = T1_TYPE_MQ; + OPJ_FLOAT64 tempwmsedec; max = 0; for (i = 0; i < t1->w * t1->h; ++i) { - int tmp = abs(t1->data[i]); + OPJ_INT32 tmp = abs(t1->data[i]); max = int_max(max, tmp); } @@ -831,8 +867,8 @@ static void t1_encode_cblk( for (passno = 0; bpno >= 0; ++passno) { opj_tcd_pass_t *pass = &cblk->passes[passno]; - int correction = 3; - type = ((bpno < (cblk->numbps - 4)) && (passtype < 2) && (cblksty & J2K_CCP_CBLKSTY_LAZY)) ? T1_TYPE_RAW : T1_TYPE_MQ; + OPJ_UINT32 correction = 3; + type = ((bpno < ((OPJ_INT32) (cblk->numbps) - 4)) && (passtype < 2) && (cblksty & J2K_CCP_CBLKSTY_LAZY)) ? T1_TYPE_RAW : T1_TYPE_MQ; switch (passtype) { case 0: @@ -850,7 +886,7 @@ static void t1_encode_cblk( } /* fixed_quality */ - tempwmsedec = t1_getwmsedec(nmsedec, compno, level, orient, bpno, qmfbid, stepsize, numcomps); + tempwmsedec = t1_getwmsedec(nmsedec, compno, level, orient, bpno, qmfbid, stepsize, numcomps,mct_norms) ; cumwmsedec += tempwmsedec; tile->distotile += tempwmsedec; @@ -866,7 +902,7 @@ static void t1_encode_cblk( } pass->term = 1; } else { - if (((bpno < (cblk->numbps - 4) && (passtype > 0)) + if (((bpno < ((OPJ_INT32) (cblk->numbps) - 4) && (passtype > 0)) || ((bpno == (cblk->numbps - 4)) && (passtype == 2))) && (cblksty & J2K_CCP_CBLKSTY_LAZY)) { if (type == T1_TYPE_RAW) { mqc_flush(mqc); @@ -888,7 +924,7 @@ static void t1_encode_cblk( } if (pass->term && bpno > 0) { - type = ((bpno < (cblk->numbps - 4)) && (passtype < 2) && (cblksty & J2K_CCP_CBLKSTY_LAZY)) ? T1_TYPE_RAW : T1_TYPE_MQ; + type = ((bpno < ((OPJ_INT32) (cblk->numbps) - 4)) && (passtype < 2) && (cblksty & J2K_CCP_CBLKSTY_LAZY)) ? T1_TYPE_RAW : T1_TYPE_MQ; if (type == T1_TYPE_RAW) mqc_bypass_init_enc(mqc); else @@ -926,16 +962,17 @@ static void t1_encode_cblk( static void t1_decode_cblk( opj_t1_t *t1, opj_tcd_cblk_dec_t* cblk, - int orient, - int roishift, - int cblksty) + OPJ_UINT32 orient, + OPJ_UINT32 roishift, + OPJ_UINT32 cblksty) { opj_raw_t *raw = t1->raw; /* RAW component */ opj_mqc_t *mqc = t1->mqc; /* MQC component */ - int bpno, passtype; - int segno, passno; - char type = T1_TYPE_MQ; /* BYPASS mode */ + OPJ_INT32 bpno; + OPJ_UINT32 passtype; + OPJ_UINT32 segno, passno; + OPJ_BYTE type = T1_TYPE_MQ; /* BYPASS mode */ if(!allocate_buffers( t1, @@ -953,13 +990,13 @@ static void t1_decode_cblk( mqc_setstate(mqc, T1_CTXNO_AGG, 0, 3); mqc_setstate(mqc, T1_CTXNO_ZC, 0, 4); - for (segno = 0; segno < cblk->numsegs; ++segno) { + for (segno = 0; segno < cblk->real_num_segs; ++segno) { opj_tcd_seg_t *seg = &cblk->segs[segno]; /* BYPASS mode */ - type = ((bpno <= (cblk->numbps - 1) - 4) && (passtype < 2) && (cblksty & J2K_CCP_CBLKSTY_LAZY)) ? T1_TYPE_RAW : T1_TYPE_MQ; + type = ((bpno <= ((OPJ_INT32) (cblk->numbps) - 1) - 4) && (passtype < 2) && (cblksty & J2K_CCP_CBLKSTY_LAZY)) ? T1_TYPE_RAW : T1_TYPE_MQ; /* FIXME: slviewer gets here with a null pointer. Why? Partially downloaded and/or corrupt textures? */ - if(seg->data == NULL){ + if(seg->data == 00){ continue; } if (type == T1_TYPE_RAW) { @@ -968,7 +1005,7 @@ static void t1_decode_cblk( mqc_init_dec(mqc, (*seg->data) + seg->dataindex, seg->len); } - for (passno = 0; passno < seg->numpasses; ++passno) { + for (passno = 0; passno < seg->real_num_passes; ++passno) { switch (passtype) { case 0: t1_dec_sigpass(t1, bpno+1, orient, type, cblksty); @@ -996,49 +1033,88 @@ static void t1_decode_cblk( } /* ----------------------------------------------------------------------- */ +/** + * 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() +{ + opj_t1_t *l_t1 = 00; -opj_t1_t* t1_create(opj_common_ptr cinfo) { - opj_t1_t *t1 = (opj_t1_t*) opj_malloc(sizeof(opj_t1_t)); - if(!t1) - return NULL; + l_t1 = (opj_t1_t*) opj_malloc(sizeof(opj_t1_t)); + if + (!l_t1) + { + return 00; + } + memset(l_t1,0,sizeof(opj_t1_t)); - t1->cinfo = cinfo; /* create MQC and RAW handles */ - t1->mqc = mqc_create(); - t1->raw = raw_create(); - - t1->data=NULL; - t1->flags=NULL; - t1->datasize=0; - t1->flagssize=0; - - return t1; + 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; } -void t1_destroy(opj_t1_t *t1) { - if(t1) { - /* destroy MQC and RAW handles */ - mqc_destroy(t1->mqc); - raw_destroy(t1->raw); - opj_aligned_free(t1->data); - opj_aligned_free(t1->flags); - opj_free(t1); +/** + * Destroys a previously created T1 handle + * + * @param p_t1 Tier 1 handle to destroy +*/ +void t1_destroy(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); } -void t1_encode_cblks( +bool t1_encode_cblks( opj_t1_t *t1, opj_tcd_tile_t *tile, - opj_tcp_t *tcp) + opj_tcp_t *tcp, + const OPJ_FLOAT64 * mct_norms) { - int compno, resno, bandno, precno, cblkno; + OPJ_UINT32 compno, resno, bandno, precno, cblkno; tile->distotile = 0; /* fixed_quality */ for (compno = 0; compno < tile->numcomps; ++compno) { opj_tcd_tilecomp_t* tilec = &tile->comps[compno]; opj_tccp_t* tccp = &tcp->tccps[compno]; - int tile_w = tilec->x1 - tilec->x0; + OPJ_UINT32 tile_w = tilec->x1 - tilec->x0; for (resno = 0; resno < tilec->numresolutions; ++resno) { opj_tcd_resolution_t *res = &tilec->resolutions[resno]; @@ -1051,14 +1127,14 @@ void t1_encode_cblks( for (cblkno = 0; cblkno < prc->cw * prc->ch; ++cblkno) { opj_tcd_cblk_enc_t* cblk = &prc->cblks.enc[cblkno]; - int* restrict datap; - int* restrict tiledp; - int cblk_w; - int cblk_h; - int i, j; - - int x = cblk->x0 - band->x0; - int y = cblk->y0 - band->y0; + OPJ_INT32 * restrict datap; + OPJ_INT32* restrict tiledp; + OPJ_UINT32 cblk_w; + OPJ_UINT32 cblk_h; + OPJ_UINT32 i, j; + + OPJ_INT32 x = cblk->x0 - band->x0; + OPJ_INT32 y = cblk->y0 - band->y0; if (band->bandno & 1) { opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; x += pres->x1 - pres->x0; @@ -1073,7 +1149,7 @@ void t1_encode_cblks( cblk->x1 - cblk->x0, cblk->y1 - cblk->y0)) { - return; + return false; } datap=t1->data; @@ -1084,18 +1160,18 @@ void t1_encode_cblks( if (tccp->qmfbid == 1) { for (j = 0; j < cblk_h; ++j) { for (i = 0; i < cblk_w; ++i) { - int tmp = tiledp[(j * tile_w) + i]; + OPJ_INT32 tmp = tiledp[(j * tile_w) + i]; datap[(j * cblk_w) + i] = tmp << T1_NMSEDEC_FRACBITS; } } } else { /* if (tccp->qmfbid == 0) */ for (j = 0; j < cblk_h; ++j) { for (i = 0; i < cblk_w; ++i) { - int tmp = tiledp[(j * tile_w) + i]; + OPJ_INT32 tmp = tiledp[(j * tile_w) + i]; datap[(j * cblk_w) + i] = fix_mul( tmp, - 8192 * 8192 / ((int) floor(band->stepsize * 8192))) >> (11 - T1_NMSEDEC_FRACBITS); + 8192 * 8192 / ((OPJ_INT32) floor(band->stepsize * 8192))) >> (11 - T1_NMSEDEC_FRACBITS); } } } @@ -1110,13 +1186,15 @@ void t1_encode_cblks( band->stepsize, tccp->cblksty, tile->numcomps, - tile); + tile, + mct_norms); } /* cblkno */ } /* precno */ } /* bandno */ } /* resno */ } /* compno */ + return true; } void t1_decode_cblks( @@ -1124,11 +1202,11 @@ void t1_decode_cblks( opj_tcd_tilecomp_t* tilec, opj_tccp_t* tccp) { - int resno, bandno, precno, cblkno; + OPJ_UINT32 resno, bandno, precno, cblkno; - int tile_w = tilec->x1 - tilec->x0; + OPJ_UINT32 tile_w = tilec->x1 - tilec->x0; - for (resno = 0; resno < tilec->numresolutions; ++resno) { + for (resno = 0; resno < tilec->minimum_num_resolutions; ++resno) { opj_tcd_resolution_t* res = &tilec->resolutions[resno]; for (bandno = 0; bandno < res->numbands; ++bandno) { @@ -1139,11 +1217,11 @@ void t1_decode_cblks( for (cblkno = 0; cblkno < precinct->cw * precinct->ch; ++cblkno) { opj_tcd_cblk_dec_t* cblk = &precinct->cblks.dec[cblkno]; - int* restrict datap; + OPJ_INT32* restrict datap; void* restrict tiledp; - int cblk_w, cblk_h; - int x, y; - int i, j; + OPJ_UINT32 cblk_w, cblk_h; + OPJ_INT32 x, y; + OPJ_UINT32 i, j; t1_decode_cblk( t1, @@ -1168,11 +1246,11 @@ void t1_decode_cblks( cblk_h = t1->h; if (tccp->roishift) { - int thresh = 1 << tccp->roishift; + OPJ_INT32 thresh = 1 << tccp->roishift; for (j = 0; j < cblk_h; ++j) { for (i = 0; i < cblk_w; ++i) { - int val = datap[(j * cblk_w) + i]; - int mag = abs(val); + OPJ_INT32 val = datap[(j * cblk_w) + i]; + OPJ_INT32 mag = abs(val); if (mag >= thresh) { mag >>= tccp->roishift; datap[(j * cblk_w) + i] = val < 0 ? -mag : mag; @@ -1185,8 +1263,8 @@ void t1_decode_cblks( if (tccp->qmfbid == 1) { for (j = 0; j < cblk_h; ++j) { for (i = 0; i < cblk_w; ++i) { - int tmp = datap[(j * cblk_w) + i]; - ((int*)tiledp)[(j * tile_w) + i] = tmp / 2; + OPJ_INT32 tmp = datap[(j * cblk_w) + i]; + ((OPJ_INT32*)tiledp)[(j * tile_w) + i] = tmp >> 1; } } } else { /* if (tccp->qmfbid == 0) */ @@ -1197,12 +1275,12 @@ void t1_decode_cblks( } } } - opj_free(cblk->data); - opj_free(cblk->segs); + //opj_free(cblk->segs); + //cblk->segs = 00; } /* cblkno */ - opj_free(precinct->cblks.dec); } /* precno */ } /* bandno */ } /* resno */ } + diff --git a/libopenjpeg/t1.h b/libopenjpeg/t1.h index 0b4294e1..1a4402c8 100644 --- a/libopenjpeg/t1.h +++ b/libopenjpeg/t1.h @@ -5,6 +5,7 @@ * Copyright (c) 2002-2003, Yannick Verschueren * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,10 +38,10 @@ The functions in T1.C have for goal to realize the tier-1 coding operation. The functions in T1.C are used by some function in TCD.C. */ - +#include "openjpeg.h" /** @defgroup T1 T1 - Implementation of the tier-1 coding */ /*@{*/ - +//#include "raw.h" /* ----------------------------------------------------------------------- */ #define T1_NMSEDEC_BITS 7 @@ -84,6 +85,14 @@ in T1.C are used by some function in TCD.C. #define T1_TYPE_RAW 1 /**< No encoding the information is store under raw format in codestream (mode switch RAW)*/ /* ----------------------------------------------------------------------- */ +struct opj_common_struct; +struct opj_tcd_tile; +struct opj_tcp; +struct opj_tcd_tilecomp; +struct opj_mqc; +struct opj_raw; +struct opj_tccp; + typedef short flag_t; @@ -91,21 +100,18 @@ typedef short flag_t; Tier-1 coding (coding of code-block coefficients) */ typedef struct opj_t1 { - /** codec context */ - opj_common_ptr cinfo; - /** MQC component */ - opj_mqc_t *mqc; + struct opj_mqc *mqc; /** RAW component */ - opj_raw_t *raw; + struct opj_raw *raw; - int *data; + OPJ_INT32 *data; flag_t *flags; - int w; - int h; - int datasize; - int flagssize; - int flags_stride; + OPJ_UINT32 w; + OPJ_UINT32 h; + OPJ_UINT32 datasize; + OPJ_UINT32 flagssize; + OPJ_UINT32 flags_stride; } opj_t1_t; #define MACRO_t1_flags(x,y) t1->flags[((x)*(t1->flags_stride))+(y)] @@ -113,32 +119,35 @@ typedef struct opj_t1 { /** @name Exported functions */ /*@{*/ /* ----------------------------------------------------------------------- */ + /** -Create a new T1 handle -and initialize the look-up tables of the Tier-1 coder/decoder -@return Returns a new T1 handle if successful, returns NULL otherwise -@see t1_init_luts + * 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(opj_common_ptr cinfo); +opj_t1_t* t1_create(); + /** -Destroy a previously created T1 handle -@param t1 T1 handle to destroy + * Destroys a previously created T1 handle + * + * @param p_t1 Tier 1 handle to destroy */ -void t1_destroy(opj_t1_t *t1); +void t1_destroy(opj_t1_t *p_t1); + /** Encode the code-blocks of a tile @param t1 T1 handle @param tile The tile to encode @param tcp Tile coding parameters */ -void t1_encode_cblks(opj_t1_t *t1, opj_tcd_tile_t *tile, opj_tcp_t *tcp); +bool t1_encode_cblks(opj_t1_t *t1, struct opj_tcd_tile *tile, struct opj_tcp *tcp,const OPJ_FLOAT64 * mct_norms); /** Decode the code-blocks of a tile @param t1 T1 handle @param tile The tile to decode @param tcp Tile coding parameters */ -void t1_decode_cblks(opj_t1_t* t1, opj_tcd_tilecomp_t* tilec, opj_tccp_t* tccp); +void t1_decode_cblks(opj_t1_t* t1, struct opj_tcd_tilecomp* tilec, struct opj_tccp* tccp); /* ----------------------------------------------------------------------- */ /*@}*/ diff --git a/libopenjpeg/t2.c b/libopenjpeg/t2.c index be9b42a4..18397e33 100644 --- a/libopenjpeg/t2.c +++ b/libopenjpeg/t2.c @@ -5,6 +5,7 @@ * Copyright (c) 2002-2003, Yannick Verschueren * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,8 +29,19 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ - +#include "openjpeg.h" #include "opj_includes.h" +#include "t2.h" +#include "bio.h" +#include "tcd.h" +#include "pi.h" +#include "event.h" +#include "j2k.h" +#include "tgt.h" +#include "int.h" +#include "opj_malloc.h" +#include "pi.h" + /** @defgroup T2 T2 - Implementation of a tier-2 coding */ /*@{*/ @@ -37,15 +49,15 @@ /** @name Local static functions */ /*@{*/ -static void t2_putcommacode(opj_bio_t *bio, int n); -static int t2_getcommacode(opj_bio_t *bio); +static void t2_putcommacode(opj_bio_t *bio, OPJ_UINT32 n); +static OPJ_UINT32 t2_getcommacode(opj_bio_t *bio); /** Variable length code for signalling delta Zil (truncation point) @param bio Bit Input/Output component @param n delta Zil */ -static void t2_putnumpasses(opj_bio_t *bio, int n); -static int t2_getnumpasses(opj_bio_t *bio); +static void t2_putnumpasses(opj_bio_t *bio, OPJ_UINT32 n); +static OPJ_UINT32 t2_getnumpasses(opj_bio_t *bio); /** Encode a packet of a tile to a destination buffer @param tile Tile for which to write the packets @@ -57,13 +69,21 @@ Encode a packet of a tile to a destination buffer @param tileno Number of the tile encoded @return */ -static int t2_encode_packet(opj_tcd_tile_t *tile, opj_tcp_t *tcp, opj_pi_iterator_t *pi, unsigned char *dest, int len, opj_codestream_info_t *cstr_info, int tileno); +static bool t2_encode_packet( + OPJ_UINT32 tileno, + opj_tcd_tile_t *tile, + opj_tcp_t *tcp, + opj_pi_iterator_t *pi, + OPJ_BYTE *dest, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 len, + opj_codestream_info_t *cstr_info); /** @param seg @param cblksty @param first */ -static void t2_init_seg(opj_tcd_cblk_dec_t* cblk, int index, int cblksty, int first); +static bool t2_init_seg(opj_tcd_cblk_dec_t* cblk, OPJ_UINT32 index, OPJ_UINT32 cblksty, OPJ_UINT32 first); /** Decode a packet of a tile from a source buffer @param t2 T2 handle @@ -74,8 +94,15 @@ Decode a packet of a tile from a source buffer @param pi Packet identity @return */ -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); +static bool t2_decode_packet( + opj_t2_t* p_t2, + opj_tcd_tile_t *p_tile, + opj_tcp_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); /*@}*/ @@ -85,22 +112,26 @@ static int t2_decode_packet(opj_t2_t* t2, unsigned char *src, int len, opj_tcd_t /* #define RESTART 0x04 */ -static void t2_putcommacode(opj_bio_t *bio, int n) { - while (--n >= 0) { +static void t2_putcommacode(opj_bio_t *bio, OPJ_UINT32 n) { + while + (--n != -1) + { bio_write(bio, 1, 1); } bio_write(bio, 0, 1); } -static int t2_getcommacode(opj_bio_t *bio) { - int n; - for (n = 0; bio_read(bio, 1); n++) { - ; +static OPJ_UINT32 t2_getcommacode(opj_bio_t *bio) { + OPJ_UINT32 n = 0; + while + (bio_read(bio, 1)) + { + ++n; } return n; } -static void t2_putnumpasses(opj_bio_t *bio, int n) { +static void t2_putnumpasses(opj_bio_t *bio, OPJ_UINT32 n) { if (n == 1) { bio_write(bio, 0, 1); } else if (n == 2) { @@ -114,8 +145,8 @@ static void t2_putnumpasses(opj_bio_t *bio, int n) { } } -static int t2_getnumpasses(opj_bio_t *bio) { - int n; +static OPJ_UINT32 t2_getnumpasses(opj_bio_t *bio) { + OPJ_UINT32 n; if (!bio_read(bio, 1)) return 1; if (!bio_read(bio, 1)) @@ -127,19 +158,32 @@ static int t2_getnumpasses(opj_bio_t *bio) { return (37 + bio_read(bio, 7)); } -static int t2_encode_packet(opj_tcd_tile_t * tile, opj_tcp_t * tcp, opj_pi_iterator_t *pi, unsigned char *dest, int length, opj_codestream_info_t *cstr_info, int tileno) { - int bandno, cblkno; - unsigned char *c = dest; - - int compno = pi->compno; /* component value */ - int resno = pi->resno; /* resolution level value */ - int precno = pi->precno; /* precinct value */ - int layno = pi->layno; /* quality layer value */ +static bool t2_encode_packet( + OPJ_UINT32 tileno, + opj_tcd_tile_t * tile, + opj_tcp_t * tcp, + opj_pi_iterator_t *pi, + OPJ_BYTE *dest, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 length, + opj_codestream_info_t *cstr_info) +{ + OPJ_UINT32 bandno, cblkno; + OPJ_BYTE *c = dest; + OPJ_UINT32 l_nb_bytes; + OPJ_UINT32 compno = pi->compno; /* component value */ + OPJ_UINT32 resno = pi->resno; /* resolution level value */ + OPJ_UINT32 precno = pi->precno; /* precinct value */ + OPJ_UINT32 layno = pi->layno; /* quality layer value */ + OPJ_UINT32 l_nb_blocks; + opj_tcd_band_t *band = 00; + opj_tcd_cblk_enc_t* cblk = 00; + opj_tcd_pass_t *pass = 00; opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; opj_tcd_resolution_t *res = &tilec->resolutions[resno]; - opj_bio_t *bio = NULL; /* BIO component */ + opj_bio_t *bio = 00; /* BIO component */ /* <SOP 0xff91> */ if (tcp->csty & J2K_CP_CSTY_SOP) { @@ -150,20 +194,27 @@ static int t2_encode_packet(opj_tcd_tile_t * tile, opj_tcp_t * tcp, opj_pi_itera c[4] = (tile->packno % 65536) / 256; c[5] = (tile->packno % 65536) % 256; c += 6; + length -= 6; } /* </SOP> */ if (!layno) { - for (bandno = 0; bandno < res->numbands; bandno++) { - opj_tcd_band_t *band = &res->bands[bandno]; + band = res->bands; + for + (bandno = 0; bandno < res->numbands; ++bandno) + { opj_tcd_precinct_t *prc = &band->precincts[precno]; tgt_reset(prc->incltree); tgt_reset(prc->imsbtree); - for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + l_nb_blocks = prc->cw * prc->ch; + for + (cblkno = 0; cblkno < l_nb_blocks; ++cblkno) + { opj_tcd_cblk_enc_t* cblk = &prc->cblks.enc[cblkno]; cblk->numpasses = 0; tgt_setvalue(prc->imsbtree, cblkno, band->numbps - cblk->numbps); } + ++band; } } @@ -172,22 +223,32 @@ static int t2_encode_packet(opj_tcd_tile_t * tile, opj_tcp_t * tcp, opj_pi_itera bio_write(bio, 1, 1); /* Empty header bit */ /* Writing Packet header */ - for (bandno = 0; bandno < res->numbands; bandno++) { - opj_tcd_band_t *band = &res->bands[bandno]; + band = res->bands; + for + (bandno = 0; bandno < res->numbands; ++bandno) + { opj_tcd_precinct_t *prc = &band->precincts[precno]; - for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { - opj_tcd_cblk_enc_t* cblk = &prc->cblks.enc[cblkno]; + l_nb_blocks = prc->cw * prc->ch; + cblk = prc->cblks.enc; + for (cblkno = 0; cblkno < l_nb_blocks; ++cblkno) + { opj_tcd_layer_t *layer = &cblk->layers[layno]; - if (!cblk->numpasses && layer->numpasses) { + if + (!cblk->numpasses && layer->numpasses) + { tgt_setvalue(prc->incltree, cblkno, layno); } + ++cblk; } - for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { - opj_tcd_cblk_enc_t* cblk = &prc->cblks.enc[cblkno]; + cblk = prc->cblks.enc; + for + (cblkno = 0; cblkno < l_nb_blocks; cblkno++) + { opj_tcd_layer_t *layer = &cblk->layers[layno]; - int increment = 0; - int nump = 0; - int len = 0, passno; + OPJ_UINT32 increment = 0; + OPJ_UINT32 nump = 0; + OPJ_UINT32 len = 0, passno; + OPJ_UINT32 l_nb_passes; /* cblk inclusion bits */ if (!cblk->numpasses) { tgt_encode(bio, prc->incltree, cblkno, layno + 1); @@ -195,53 +256,73 @@ static int t2_encode_packet(opj_tcd_tile_t * tile, opj_tcp_t * tcp, opj_pi_itera bio_write(bio, layer->numpasses != 0, 1); } /* if cblk not included, go to the next cblk */ - if (!layer->numpasses) { + if + (!layer->numpasses) + { + ++cblk; continue; } /* if first instance of cblk --> zero bit-planes information */ - if (!cblk->numpasses) { + if + (!cblk->numpasses) + { cblk->numlenbits = 3; tgt_encode(bio, prc->imsbtree, cblkno, 999); } /* number of coding passes included */ t2_putnumpasses(bio, layer->numpasses); - + l_nb_passes = cblk->numpasses + layer->numpasses; + pass = cblk->passes + cblk->numpasses; /* computation of the increase of the length indicator and insertion in the header */ - for (passno = cblk->numpasses; passno < cblk->numpasses + layer->numpasses; passno++) { - opj_tcd_pass_t *pass = &cblk->passes[passno]; - nump++; + for + (passno = cblk->numpasses; passno < l_nb_passes; ++passno) + { + ++nump; len += pass->len; - if (pass->term || passno == (cblk->numpasses + layer->numpasses) - 1) { + if + (pass->term || passno == (cblk->numpasses + layer->numpasses) - 1) + { increment = int_max(increment, int_floorlog2(len) + 1 - (cblk->numlenbits + int_floorlog2(nump))); len = 0; nump = 0; } + ++pass; } t2_putcommacode(bio, increment); /* computation of the new Length indicator */ cblk->numlenbits += increment; + pass = cblk->passes + cblk->numpasses; /* insertion of the codeword segment length */ - for (passno = cblk->numpasses; passno < cblk->numpasses + layer->numpasses; passno++) { - opj_tcd_pass_t *pass = &cblk->passes[passno]; + for + (passno = cblk->numpasses; passno < l_nb_passes; ++passno) + { nump++; len += pass->len; - if (pass->term || passno == (cblk->numpasses + layer->numpasses) - 1) { + if + (pass->term || passno == (cblk->numpasses + layer->numpasses) - 1) + { bio_write(bio, len, cblk->numlenbits + int_floorlog2(nump)); len = 0; nump = 0; } + ++pass; } + ++cblk; } + ++band; } - if (bio_flush(bio)) { + if + (bio_flush(bio)) + { bio_destroy(bio); - return -999; /* modified to eliminate longjmp !! */ + return false; /* modified to eliminate longjmp !! */ } - - c += bio_numbytes(bio); + l_nb_bytes = bio_numbytes(bio); + c += l_nb_bytes; + length -= l_nb_bytes; bio_destroy(bio); /* <EPH 0xff92> */ @@ -249,6 +330,7 @@ static int t2_encode_packet(opj_tcd_tile_t * tile, opj_tcp_t * tcp, opj_pi_itera c[0] = 255; c[1] = 146; c += 2; + length -= 2; } /* </EPH> */ @@ -257,28 +339,37 @@ static int t2_encode_packet(opj_tcd_tile_t * tile, opj_tcp_t * tcp, opj_pi_itera // Will be updated later by incrementing with packet start value if(cstr_info && cstr_info->index_write) { opj_packet_info_t *info_PK = &cstr_info->tile[tileno].packet[cstr_info->packno]; - info_PK->end_ph_pos = (int)(c - dest); + info_PK->end_ph_pos = (OPJ_INT32)(c - dest); } /* INDEX >> */ /* Writing the packet body */ - - for (bandno = 0; bandno < res->numbands; bandno++) { - opj_tcd_band_t *band = &res->bands[bandno]; + band = res->bands; + for + (bandno = 0; bandno < res->numbands; bandno++) + { opj_tcd_precinct_t *prc = &band->precincts[precno]; - for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { - opj_tcd_cblk_enc_t* cblk = &prc->cblks.enc[cblkno]; + l_nb_blocks = prc->cw * prc->ch; + cblk = prc->cblks.enc; + for + (cblkno = 0; cblkno < l_nb_blocks; ++cblkno) + { opj_tcd_layer_t *layer = &cblk->layers[layno]; - if (!layer->numpasses) { + if + (!layer->numpasses) + { + ++cblk; continue; } - if (c + layer->len > dest + length) { - return -999; + if + (layer->len > length) + { + return false; } - memcpy(c, layer->data, layer->len); cblk->numpasses += layer->numpasses; c += layer->len; + length -= layer->len; /* << INDEX */ if(cstr_info && cstr_info->index_write) { opj_packet_info_t *info_PK = &cstr_info->tile[tileno].packet[cstr_info->packno]; @@ -287,21 +378,34 @@ static int t2_encode_packet(opj_tcd_tile_t * tile, opj_tcp_t * tcp, opj_pi_itera cstr_info->D_max = info_PK->disto; } } + ++cblk; /* INDEX >> */ } + ++band; } - - return (c - dest); + * p_data_written += (c - dest); + return true; } -static void t2_init_seg(opj_tcd_cblk_dec_t* cblk, int index, int cblksty, int first) { - opj_tcd_seg_t* seg; - cblk->segs = (opj_tcd_seg_t*) opj_realloc(cblk->segs, (index + 1) * sizeof(opj_tcd_seg_t)); +static bool t2_init_seg(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 false; + } + } seg = &cblk->segs[index]; - seg->data = NULL; - seg->dataindex = 0; - seg->numpasses = 0; - seg->len = 0; + memset(seg,0,sizeof(opj_tcd_seg_t)); + if (cblksty & J2K_CCP_CBLKSTY_TERMALL) { seg->maxpasses = 1; } @@ -314,50 +418,74 @@ static void t2_init_seg(opj_tcd_cblk_dec_t* cblk, int index, int cblksty, int fi } else { seg->maxpasses = 109; } + return true; } -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) { - int bandno, cblkno; - unsigned char *c = src; - - opj_cp_t *cp = t2->cp; - - int compno = pi->compno; /* component value */ - int resno = pi->resno; /* resolution level value */ - int precno = pi->precno; /* precinct value */ - int layno = pi->layno; /* quality layer value */ - - opj_tcd_resolution_t* res = &tile->comps[compno].resolutions[resno]; - - unsigned char *hd = NULL; - int present; +static bool t2_read_packet_header( + opj_t2_t* p_t2, + opj_tcd_tile_t *p_tile, + opj_tcp_t *p_tcp, + opj_pi_iterator_t *p_pi, + 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_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_bio_t *bio = NULL; /* BIO component */ + OPJ_BYTE *l_header_data = 00; + OPJ_BYTE **l_header_data_start = 00; - if (layno == 0) { - for (bandno = 0; bandno < res->numbands; bandno++) { - opj_tcd_band_t *band = &res->bands[bandno]; - opj_tcd_precinct_t *prc = &band->precincts[precno]; - - if ((band->x1-band->x0 == 0)||(band->y1-band->y0 == 0)) continue; + 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]; - tgt_reset(prc->incltree); - tgt_reset(prc->imsbtree); - for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { - opj_tcd_cblk_dec_t* cblk = &prc->cblks.dec[cblkno]; - cblk->numsegs = 0; + 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 (tcp->csty & J2K_CP_CSTY_SOP) { - if ((*c) != 0xff || (*(c + 1) != 0x91)) { - opj_event_msg(t2->cinfo, EVT_WARNING, "Expected SOP marker\n"); + 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 { - c += 6; + l_current_data += 6; } /** TODO : check the Nsop value */ @@ -370,179 +498,276 @@ static int t2_decode_packet(opj_t2_t* t2, unsigned char *src, int len, opj_tcd_t step 2: Return to codestream for decoding */ - bio = bio_create(); - - if (cp->ppm == 1) { /* PPM */ - hd = cp->ppm_data; - bio_init_dec(bio, hd, cp->ppm_len); - } else if (tcp->ppt == 1) { /* PPT */ - hd = tcp->ppt_data; - bio_init_dec(bio, hd, tcp->ppt_len); - } else { /* Normal Case */ - hd = c; - bio_init_dec(bio, hd, src+len-hd); + l_bio = bio_create(); + if + (! l_bio) + { + return false; } - present = bio_read(bio, 1); - - if (!present) { - bio_inalign(bio); - hd += bio_numbytes(bio); - bio_destroy(bio); + 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 (tcp->csty & J2K_CP_CSTY_EPH) { - if ((*hd) != 0xff || (*(hd + 1) != 0x92)) { + 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 { - hd += 2; + 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(pack_info) { - pack_info->end_ph_pos = (int)(c - src); + if + (p_pack_info) + { + p_pack_info->end_ph_pos = (OPJ_INT32)(l_current_data - p_src_data); } /* INDEX >> */ - - if (cp->ppm == 1) { /* PPM case */ - cp->ppm_len += cp->ppm_data-hd; - cp->ppm_data = hd; - return (c - src); - } - if (tcp->ppt == 1) { /* PPT case */ - tcp->ppt_len+=tcp->ppt_data-hd; - tcp->ppt_data = hd; - return (c - src); - } - - return (hd - src); + * p_is_data_present = false; + *p_data_read = l_current_data - p_src_data; + return true; } - for (bandno = 0; bandno < res->numbands; bandno++) { - opj_tcd_band_t *band = &res->bands[bandno]; - opj_tcd_precinct_t *prc = &band->precincts[precno]; + 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 ((band->x1-band->x0 == 0)||(band->y1-band->y0 == 0)) continue; - - for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { - int included, increment, n, segno; - opj_tcd_cblk_dec_t* cblk = &prc->cblks.dec[cblkno]; + 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 (!cblk->numsegs) { - included = tgt_decode(bio, prc->incltree, cblkno, layno + 1); + if + (!l_cblk->numsegs) + { + l_included = tgt_decode(l_bio, l_prc->incltree, cblkno, p_pi->layno + 1); /* else one bit */ - } else { - included = bio_read(bio, 1); + } + else + { + l_included = bio_read(l_bio, 1); } /* if cblk not included */ - if (!included) { - cblk->numnewpasses = 0; + if + (!l_included) + { + l_cblk->numnewpasses = 0; + ++l_cblk; continue; } /* if cblk not yet included --> zero-bitplane tagtree */ - if (!cblk->numsegs) { - int i, numimsbs; - for (i = 0; !tgt_decode(bio, prc->imsbtree, cblkno, i); i++) { - ; + if + (!l_cblk->numsegs) + { + OPJ_UINT32 i = 0; + while + (!tgt_decode(l_bio, l_prc->imsbtree, cblkno, i)) + { + ++i; } - numimsbs = i - 1; - cblk->numbps = band->numbps - numimsbs; - cblk->numlenbits = 3; + l_cblk->numbps = l_band->numbps + 1 - i; + l_cblk->numlenbits = 3; } /* number of coding passes */ - cblk->numnewpasses = t2_getnumpasses(bio); - increment = t2_getcommacode(bio); + l_cblk->numnewpasses = t2_getnumpasses(l_bio); + l_increment = t2_getcommacode(l_bio); /* length indicator increment */ - cblk->numlenbits += increment; - segno = 0; - if (!cblk->numsegs) { - t2_init_seg(cblk, segno, tcp->tccps[compno].cblksty, 1); - } else { - segno = cblk->numsegs - 1; - if (cblk->segs[segno].numpasses == cblk->segs[segno].maxpasses) { - ++segno; - t2_init_seg(cblk, segno, tcp->tccps[compno].cblksty, 0); + l_cblk->numlenbits += l_increment; + l_segno = 0; + if + (!l_cblk->numsegs) + { + if + (! t2_init_seg(l_cblk, l_segno, p_tcp->tccps[p_pi->compno].cblksty, 1)) + { + bio_destroy(l_bio); + return 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(l_cblk, l_segno, p_tcp->tccps[p_pi->compno].cblksty, 0)) + { + bio_destroy(l_bio); + return false; + } } } - n = cblk->numnewpasses; + n = l_cblk->numnewpasses; do { - cblk->segs[segno].numnewpasses = int_min(cblk->segs[segno].maxpasses - cblk->segs[segno].numpasses, n); - cblk->segs[segno].newlen = bio_read(bio, cblk->numlenbits + int_floorlog2(cblk->segs[segno].numnewpasses)); - n -= cblk->segs[segno].numnewpasses; - if (n > 0) { - ++segno; - t2_init_seg(cblk, segno, tcp->tccps[compno].cblksty, 0); + 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(l_cblk, l_segno, p_tcp->tccps[p_pi->compno].cblksty, 0)) + { + bio_destroy(l_bio); + return false; + } } - } while (n > 0); + } + while (n > 0); + ++l_cblk; } + ++l_band; } - if (bio_inalign(bio)) { - bio_destroy(bio); - return -999; + if + (bio_inalign(l_bio)) + { + bio_destroy(l_bio); + return false; } - hd += bio_numbytes(bio); - bio_destroy(bio); + l_header_data += bio_numbytes(l_bio); + bio_destroy(l_bio); /* EPH markers */ - if (tcp->csty & J2K_CP_CSTY_EPH) { - if ((*hd) != 0xff || (*(hd + 1) != 0x92)) { - opj_event_msg(t2->cinfo, EVT_ERROR, "Expected EPH marker\n"); + 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 { - hd += 2; + 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(pack_info) { - pack_info->end_ph_pos = (int)(hd - src); + if + (p_pack_info) + { + p_pack_info->end_ph_pos = (OPJ_INT32)(l_current_data - p_src_data); } /* INDEX >> */ - - if (cp->ppm==1) { - cp->ppm_len+=cp->ppm_data-hd; - cp->ppm_data = hd; - } else if (tcp->ppt == 1) { - tcp->ppt_len+=tcp->ppt_data-hd; - tcp->ppt_data = hd; - } else { - c=hd; - } - - for (bandno = 0; bandno < res->numbands; bandno++) { - opj_tcd_band_t *band = &res->bands[bandno]; - opj_tcd_precinct_t *prc = &band->precincts[precno]; - - if ((band->x1-band->x0 == 0)||(band->y1-band->y0 == 0)) continue; + * p_is_data_present = true; + *p_data_read = l_current_data - p_src_data; + return true; +} + +static bool t2_read_packet_data( + opj_t2_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]; - for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { - opj_tcd_cblk_dec_t* cblk = &prc->cblks.dec[cblkno]; - opj_tcd_seg_t *seg = NULL; - if (!cblk->numnewpasses) + 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 (!cblk->numsegs) { - seg = &cblk->segs[0]; - cblk->numsegs++; - cblk->len = 0; - } else { - seg = &cblk->segs[cblk->numsegs - 1]; - if (seg->numpasses == seg->maxpasses) { - seg++; - cblk->numsegs++; + } + 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 (c + seg->newlen > src + len) { - return -999; + do + { + if + (l_current_data + l_seg->newlen > p_src_data + p_max_length) + { + return false; } #ifdef USE_JPWL @@ -565,99 +790,337 @@ static int t2_decode_packet(opj_t2_t* t2, unsigned char *src, int len, opj_tcd_t #endif /* USE_JPWL */ - cblk->data = (unsigned char*) opj_realloc(cblk->data, (cblk->len + seg->newlen) * sizeof(unsigned char*)); - memcpy(cblk->data + cblk->len, c, seg->newlen); - if (seg->numpasses == 0) { - seg->data = &cblk->data; - seg->dataindex = cblk->len; + 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; } - c += seg->newlen; - cblk->len += seg->newlen; - seg->len += seg->newlen; - seg->numpasses += seg->numnewpasses; - cblk->numnewpasses -= seg->numnewpasses; - if (cblk->numnewpasses > 0) { - seg++; - cblk->numsegs++; + 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 (cblk->numnewpasses > 0); + } + 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 true; +} + + +static bool t2_skip_packet_data( + opj_t2_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]; - return (c - src); + *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 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; + } + } + return true; } -/* ----------------------------------------------------------------------- */ +static bool t2_decode_packet( + opj_t2_t* p_t2, + opj_tcd_tile_t *p_tile, + opj_tcp_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) +{ + bool l_read_data; + OPJ_UINT32 l_nb_bytes_read = 0; + OPJ_UINT32 l_nb_total_bytes_read = 0; -int t2_encode_packets(opj_t2_t* t2,int tileno, opj_tcd_tile_t *tile, int maxlayers, unsigned char *dest, int len, opj_codestream_info_t *cstr_info,int tpnum, int tppos,int pino, J2K_T2_MODE t2_mode, int cur_totnum_tp){ - unsigned char *c = dest; - int e = 0; - int compno; - opj_pi_iterator_t *pi = NULL; - int poc; - opj_image_t *image = t2->image; - opj_cp_t *cp = t2->cp; - opj_tcp_t *tcp = &cp->tcps[tileno]; - int pocno = cp->cinema == CINEMA4K_24? 2: 1; - int maxcomp = cp->max_comp_size > 0 ? image->numcomps : 1; + *p_data_read = 0; - pi = pi_initialise_encode(image, cp, tileno, t2_mode); - if(!pi) { - /* TODO: throw an error */ - return -999; + 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 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 false; + } + l_nb_total_bytes_read += l_nb_bytes_read; + } + *p_data_read = l_nb_total_bytes_read; + return true; +} + +static bool t2_skip_packet( + opj_t2_t* p_t2, + opj_tcd_tile_t *p_tile, + opj_tcp_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) +{ + 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_mode == THRESH_CALC ){ /* Calculating threshold */ - for(compno = 0; compno < maxcomp; compno++ ){ - for(poc = 0; poc < pocno ; poc++){ - int comp_len = 0; - int tpnum = compno; - if (pi_create_encode(pi, cp,tileno,poc,tpnum,tppos,t2_mode,cur_totnum_tp)) { - opj_event_msg(t2->cinfo, EVT_ERROR, "Error initializing Packet Iterator\n"); - return -999; - } - while (pi_next(&pi[poc])) { - if (pi[poc].layno < maxlayers) { - e = t2_encode_packet(tile, &cp->tcps[tileno], &pi[poc], c, dest + len - c, cstr_info, tileno); - comp_len = comp_len + e; - if (e == -999) { - break; - } else { - c += e; + 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 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 false; + } + l_nb_total_bytes_read += l_nb_bytes_read; + } + *p_data_read = l_nb_total_bytes_read; + return true; +} + +/* ----------------------------------------------------------------------- */ + +bool t2_encode_packets( + opj_t2_t* p_t2, + OPJ_UINT32 p_tile_no, + opj_tcd_tile_t *p_tile, + OPJ_UINT32 p_maxlayers, + OPJ_BYTE *p_dest, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 p_max_len, + opj_codestream_info_t *cstr_info, + OPJ_UINT32 p_tp_num, + OPJ_INT32 p_tp_pos, + OPJ_UINT32 p_pino, + J2K_T2_MODE p_t2_mode) +{ + OPJ_BYTE *l_current_data = p_dest; + OPJ_UINT32 l_nb_bytes = 0; + OPJ_UINT32 compno; + OPJ_UINT32 poc; + opj_pi_iterator_t *l_pi = 00; + opj_pi_iterator_t *l_current_pi = 00; + opj_image_t *l_image = p_t2->image; + opj_cp_t *l_cp = p_t2->cp; + opj_tcp_t *l_tcp = &l_cp->tcps[p_tile_no]; + OPJ_UINT32 pocno = l_cp->m_specific_param.m_enc.m_cinema == CINEMA4K_24? 2: 1; + OPJ_UINT32 l_max_comp = l_cp->m_specific_param.m_enc.m_max_comp_size > 0 ? l_image->numcomps : 1; + OPJ_UINT32 l_nb_pocs = l_tcp->numpocs + 1; + + l_pi = pi_initialise_encode(l_image, l_cp, p_tile_no, p_t2_mode); + if + (!l_pi) + { + return false; + } + * p_data_written = 0; + if + (p_t2_mode == THRESH_CALC ) + { /* Calculating threshold */ + l_current_pi = l_pi; + for + (compno = 0; compno < l_max_comp; ++compno) + { + OPJ_UINT32 l_comp_len = 0; + l_current_pi = l_pi; + + for + (poc = 0; poc < pocno ; ++poc) + { + OPJ_UINT32 l_tp_num = compno; + pi_create_encode(l_pi, l_cp,p_tile_no,poc,l_tp_num,p_tp_pos,p_t2_mode); + while + (pi_next(l_current_pi)) + { + if + (l_current_pi->layno < p_maxlayers) + { + l_nb_bytes = 0; + if + (! t2_encode_packet(p_tile_no,p_tile, l_tcp, l_current_pi, l_current_data, &l_nb_bytes, p_max_len, cstr_info)) + { + pi_destroy(l_pi, l_nb_pocs); + return false; } + l_comp_len += l_nb_bytes; + l_current_data += l_nb_bytes; + p_max_len -= l_nb_bytes; + * p_data_written += l_nb_bytes; } } - if (e == -999) break; - if (cp->max_comp_size){ - if (comp_len > cp->max_comp_size){ - e = -999; - break; + if + (l_cp->m_specific_param.m_enc.m_max_comp_size) + { + if + (l_comp_len > l_cp->m_specific_param.m_enc.m_max_comp_size) + { + pi_destroy(l_pi, l_nb_pocs); + return false; } } + ++l_current_pi; } - if (e == -999) break; } - }else{ /* t2_mode == FINAL_PASS */ - pi_create_encode(pi, cp,tileno,pino,tpnum,tppos,t2_mode,cur_totnum_tp); - while (pi_next(&pi[pino])) { - if (pi[pino].layno < maxlayers) { - e = t2_encode_packet(tile, &cp->tcps[tileno], &pi[pino], c, dest + len - c, cstr_info, tileno); - if (e == -999) { - break; - } else { - c += e; + } + else + { /* t2_mode == FINAL_PASS */ + pi_create_encode(l_pi, l_cp,p_tile_no,p_pino,p_tp_num,p_tp_pos,p_t2_mode); + l_current_pi = &l_pi[p_pino]; + while + (pi_next(l_current_pi)) + { + if + (l_current_pi->layno < p_maxlayers) + { + l_nb_bytes=0; + if + (! t2_encode_packet(p_tile_no,p_tile, l_tcp, l_current_pi, l_current_data, &l_nb_bytes, p_max_len, cstr_info)) + { + pi_destroy(l_pi, l_nb_pocs); + return false; } + l_current_data += l_nb_bytes; + p_max_len -= l_nb_bytes; + * p_data_written += l_nb_bytes; + /* INDEX >> */ if(cstr_info) { if(cstr_info->index_write) { - opj_tile_info_t *info_TL = &cstr_info->tile[tileno]; + opj_tile_info_t *info_TL = &cstr_info->tile[p_tile_no]; opj_packet_info_t *info_PK = &info_TL->packet[cstr_info->packno]; if (!cstr_info->packno) { info_PK->start_pos = info_TL->end_header + 1; } else { - info_PK->start_pos = ((cp->tp_on | tcp->POC)&& info_PK->start_pos) ? info_PK->start_pos : info_TL->packet[cstr_info->packno - 1].end_pos + 1; + info_PK->start_pos = ((l_cp->m_specific_param.m_enc.m_tp_on | l_tcp->POC)&& info_PK->start_pos) ? info_PK->start_pos : info_TL->packet[cstr_info->packno - 1].end_pos + 1; } - info_PK->end_pos = info_PK->start_pos + e - 1; + info_PK->end_pos = info_PK->start_pos + l_nb_bytes - 1; info_PK->end_ph_pos += info_PK->start_pos - 1; // End of packet header which now only represents the distance // to start of packet is incremented by value of start of packet } @@ -665,123 +1128,163 @@ int t2_encode_packets(opj_t2_t* t2,int tileno, opj_tcd_tile_t *tile, int maxlaye cstr_info->packno++; } /* << INDEX */ - tile->packno++; + ++p_tile->packno; } } } - - pi_destroy(pi, cp, tileno); - - if (e == -999) { - return e; - } - - return (c - dest); + pi_destroy(l_pi, l_nb_pocs); + return true; } -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) { - unsigned char *c = src; - opj_pi_iterator_t *pi; - int pino, e = 0; - int n = 0, curtp = 0; - int tp_start_packno; +bool t2_decode_packets( + opj_t2_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_t *l_cp = p_t2->cp; + opj_cp_t *cp = p_t2->cp; + opj_tcp_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; - opj_image_t *image = t2->image; - opj_cp_t *cp = t2->cp; + + if + (p_cstr_info) + { + l_pack_info = p_cstr_info->tile[p_tile_no].packet; + } /* create a packet iterator */ - pi = pi_create_decode(image, cp, tileno); - if(!pi) { - /* TODO: throw an error */ - return -999; + l_pi = pi_create_decode(l_image, l_cp, p_tile_no); + if + (!l_pi) + { + return false; } tp_start_packno = 0; + l_current_pi = l_pi; - for (pino = 0; pino <= cp->tcps[tileno].numpocs; pino++) { - while (pi_next(&pi[pino])) { - if ((cp->layer==0) || (cp->layer>=((pi[pino].layno)+1))) { - opj_packet_info_t *pack_info; - if (cstr_info) - pack_info = &cstr_info->tile[tileno].packet[cstr_info->packno]; - else - pack_info = NULL; - e = t2_decode_packet(t2, c, src + len - c, tile, &cp->tcps[tileno], &pi[pino], pack_info); - } else { - e = 0; - } + for + (pino = 0; pino <= l_tcp->numpocs; ++pino) + { + while + (pi_next(l_current_pi)) + { - /* progression in resolution */ - image->comps[pi[pino].compno].resno_decoded = - (e > 0) ? - int_max(pi[pino].resno, image->comps[pi[pino].compno].resno_decoded) - : image->comps[pi[pino].compno].resno_decoded; - n++; + 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(p_t2,p_tile,l_tcp,l_current_pi,l_current_data,&l_nb_bytes_read,p_max_len,l_pack_info)) + { + pi_destroy(l_pi,l_nb_pocs); + return 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(l_pi,l_nb_pocs); + return false; + } + } + l_current_data += l_nb_bytes_read; + p_max_len -= l_nb_bytes_read; /* INDEX >> */ - if(cstr_info) { - opj_tile_info_t *info_TL = &cstr_info->tile[tileno]; - opj_packet_info_t *info_PK = &info_TL->packet[cstr_info->packno]; - if (!cstr_info->packno) { + 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[cstr_info->packno-1].end_pos >= (int)cstr_info->tile[tileno].tp[curtp].tp_end_pos){ // New tile part - info_TL->tp[curtp].tp_numpacks = cstr_info->packno - tp_start_packno; // Number of packets in previous tile-part - tp_start_packno = cstr_info->packno; + } 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 = cstr_info->tile[tileno].tp[curtp].tp_end_header+1; + info_PK->start_pos = p_cstr_info->tile[p_tile_no].tp[curtp].tp_end_header+1; } else { - info_PK->start_pos = (cp->tp_on && info_PK->start_pos) ? info_PK->start_pos : info_TL->packet[cstr_info->packno - 1].end_pos + 1; + 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 + e - 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 - // to start of packet is incremented by value of start of packet - cstr_info->packno++; + ++p_cstr_info->packno; } /* << INDEX */ - - if (e == -999) { /* ADD */ - break; - } else { - c += e; - } } + ++l_current_pi; } /* INDEX >> */ - if(cstr_info) { - cstr_info->tile[tileno].tp[curtp].tp_numpacks = cstr_info->packno - tp_start_packno; // Number of packets in last tile-part + 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(pi, cp, tileno); - - if (e == -999) { - return e; - } - - return (c - src); + pi_destroy(l_pi,l_nb_pocs); + *p_data_read = l_current_data - p_src; + return true; } /* ----------------------------------------------------------------------- */ - -opj_t2_t* t2_create(opj_common_ptr cinfo, opj_image_t *image, opj_cp_t *cp) { +/** + * 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_t* t2_create( + opj_image_t *p_image, + opj_cp_t *p_cp) +{ /* create the tcd structure */ - opj_t2_t *t2 = (opj_t2_t*)opj_malloc(sizeof(opj_t2_t)); - if(!t2) return NULL; - t2->cinfo = cinfo; - t2->image = image; - t2->cp = cp; - - return t2; + opj_t2_t *l_t2 = (opj_t2_t*)opj_malloc(sizeof(opj_t2_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); +/** + * Destroys a Tier 2 handle. + * + * @param p_t2 the Tier 2 handle to destroy +*/ +void t2_destroy(opj_t2_t *p_t2) +{ + if + (p_t2) + { + opj_free(p_t2); } } - diff --git a/libopenjpeg/t2.h b/libopenjpeg/t2.h index b15b7520..770a1df5 100644 --- a/libopenjpeg/t2.h +++ b/libopenjpeg/t2.h @@ -5,6 +5,7 @@ * Copyright (c) 2002-2003, Yannick Verschueren * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,21 +36,36 @@ @brief Implementation of a tier-2 coding (packetization of code-block data) (T2) */ +#include "openjpeg.h" + +struct opj_common_struct; +struct opj_image; +struct opj_cp; +struct opj_tcd_tile; +struct opj_codestream_info; /** @defgroup T2 T2 - Implementation of a tier-2 coding */ /*@{*/ +/** +T2 encoding mode +*/ +typedef enum T2_MODE +{ + THRESH_CALC = 0, /** Function called in Rate allocation process*/ + FINAL_PASS = 1 /** Function called in Tier 2 process*/ +} +J2K_T2_MODE; + /** Tier-2 coding */ -typedef struct opj_t2 { - /** codec context */ - opj_common_ptr cinfo; +typedef struct opj_t2 { /** Encoding: pointer to the src image. Decoding: pointer to the dst image. */ - opj_image_t *image; + struct opj_image *image; /** pointer to the image coding parameters */ - opj_cp_t *cp; + struct opj_cp *cp; } opj_t2_t; /** @name Exported functions */ @@ -68,9 +84,8 @@ Encode the packets of a tile to a destination buffer @param tpnum Tile part number of the current tile @param tppos The position of the tile part flag in the progression order @param t2_mode If == 0 In Threshold calculation ,If == 1 Final pass -@param cur_totnum_tp The total number of tile parts in the current tile */ -int t2_encode_packets(opj_t2_t* t2,int tileno, opj_tcd_tile_t *tile, int maxlayers, unsigned char *dest, int len, opj_codestream_info_t *cstr_info,int tpnum, int tppos,int pino,J2K_T2_MODE t2_mode,int cur_totnum_tp); +bool t2_encode_packets(opj_t2_t* t2,OPJ_UINT32 tileno, struct opj_tcd_tile *tile, OPJ_UINT32 maxlayers, OPJ_BYTE *dest, OPJ_UINT32 * p_data_written, OPJ_UINT32 len, struct opj_codestream_info *cstr_info,OPJ_UINT32 tpnum, OPJ_INT32 tppos,OPJ_UINT32 pino,J2K_T2_MODE t2_mode); /** Decode the packets of a tile from a source buffer @param t2 T2 handle @@ -79,19 +94,21 @@ Decode the packets of a tile from a source buffer @param tileno number that identifies the tile for which to decode the packets @param tile tile for which to decode the packets */ -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); +bool t2_decode_packets(opj_t2_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); /** -Create a T2 handle -@param cinfo Codec context info -@param image Source or destination image -@param cp Image coding parameters -@return Returns a new T2 handle if successful, returns NULL otherwise + * 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_t* t2_create(opj_common_ptr cinfo, opj_image_t *image, opj_cp_t *cp); +opj_t2_t* t2_create(struct opj_image *p_image, struct opj_cp *p_cp); + /** -Destroy a T2 handle -@param t2 T2 handle to destroy + * Destroys a Tier 2 handle. + * + * @param p_t2 the Tier 2 handle to destroy */ void t2_destroy(opj_t2_t *t2); diff --git a/libopenjpeg/tcd.c b/libopenjpeg/tcd.c index 01ee3950..1cfbc5af 100644 --- a/libopenjpeg/tcd.c +++ b/libopenjpeg/tcd.c @@ -6,6 +6,7 @@ * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe * Copyright (c) 2005, Herve Drolon, FreeImage Team * Copyright (c) 2006-2007, Parvatha Elangovan + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,827 +31,743 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include "tcd.h" +#include "openjpeg.h" +#include "j2k.h" #include "opj_includes.h" +#include "event.h" +#include "t2.h" +#include "t1.h" +#include "opj_malloc.h" +#include "int.h" +#include "tgt.h" +#include "dwt.h" +#include "mct.h" +#include "j2k_lib.h" +#include "profile.h" -void tcd_dump(FILE *fd, opj_tcd_t *tcd, opj_tcd_image_t * img) { - int tileno, compno, resno, bandno, precno;//, cblkno; - - fprintf(fd, "image {\n"); - fprintf(fd, " tw=%d, th=%d x0=%d x1=%d y0=%d y1=%d\n", - img->tw, img->th, tcd->image->x0, tcd->image->x1, tcd->image->y0, tcd->image->y1); - - for (tileno = 0; tileno < img->th * img->tw; tileno++) { - opj_tcd_tile_t *tile = &tcd->tcd_image->tiles[tileno]; - fprintf(fd, " tile {\n"); - fprintf(fd, " x0=%d, y0=%d, x1=%d, y1=%d, numcomps=%d\n", - tile->x0, tile->y0, tile->x1, tile->y1, tile->numcomps); - for (compno = 0; compno < tile->numcomps; compno++) { - opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; - fprintf(fd, " tilec {\n"); - fprintf(fd, - " x0=%d, y0=%d, x1=%d, y1=%d, numresolutions=%d\n", - tilec->x0, tilec->y0, tilec->x1, tilec->y1, tilec->numresolutions); - for (resno = 0; resno < tilec->numresolutions; resno++) { - opj_tcd_resolution_t *res = &tilec->resolutions[resno]; - fprintf(fd, "\n res {\n"); - fprintf(fd, - " x0=%d, y0=%d, x1=%d, y1=%d, pw=%d, ph=%d, numbands=%d\n", - res->x0, res->y0, res->x1, res->y1, res->pw, res->ph, res->numbands); - for (bandno = 0; bandno < res->numbands; bandno++) { - opj_tcd_band_t *band = &res->bands[bandno]; - fprintf(fd, " band {\n"); - fprintf(fd, - " x0=%d, y0=%d, x1=%d, y1=%d, stepsize=%f, numbps=%d\n", - band->x0, band->y0, band->x1, band->y1, band->stepsize, band->numbps); - for (precno = 0; precno < res->pw * res->ph; precno++) { - opj_tcd_precinct_t *prec = &band->precincts[precno]; - fprintf(fd, " prec {\n"); - fprintf(fd, - " x0=%d, y0=%d, x1=%d, y1=%d, cw=%d, ch=%d\n", - prec->x0, prec->y0, prec->x1, prec->y1, prec->cw, prec->ch); - /* - for (cblkno = 0; cblkno < prec->cw * prec->ch; cblkno++) { - opj_tcd_cblk_t *cblk = &prec->cblks[cblkno]; - fprintf(fd, " cblk {\n"); - fprintf(fd, - " x0=%d, y0=%d, x1=%d, y1=%d\n", - cblk->x0, cblk->y0, cblk->x1, cblk->y1); - fprintf(fd, " }\n"); - } - */ - fprintf(fd, " }\n"); - } - fprintf(fd, " }\n"); - } - fprintf(fd, " }\n"); - } - fprintf(fd, " }\n"); - } - fprintf(fd, " }\n"); - } - fprintf(fd, "}\n"); -} +/** + * Deallocates the encoding data of the given precinct. + */ +static void tcd_code_block_enc_deallocate (opj_tcd_precinct_t * p_precinct); +/** + * Allocates memory for an encoding code block. + */ +static bool tcd_code_block_enc_allocate (opj_tcd_cblk_enc_t * p_code_block); +/** + * Allocates memory for a decoding code block. + */ +static 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_t *tcd); /* ----------------------------------------------------------------------- */ /** Create a new TCD handle */ -opj_tcd_t* tcd_create(opj_common_ptr cinfo) { +opj_tcd_t* tcd_create(bool p_is_decoder) +{ + opj_tcd_t *l_tcd = 00; + /* create the tcd structure */ - opj_tcd_t *tcd = (opj_tcd_t*)opj_malloc(sizeof(opj_tcd_t)); - if(!tcd) return NULL; - tcd->cinfo = cinfo; - tcd->tcd_image = (opj_tcd_image_t*)opj_malloc(sizeof(opj_tcd_image_t)); - if(!tcd->tcd_image) { - opj_free(tcd); - return NULL; + l_tcd = (opj_tcd_t*) opj_malloc(sizeof(opj_tcd_t)); + if + (!l_tcd) + { + return 00; } - - return tcd; + memset(l_tcd,0,sizeof(opj_tcd_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 */ void tcd_destroy(opj_tcd_t *tcd) { - if(tcd) { - opj_free(tcd->tcd_image); + 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) \ +bool FUNCTION \ + ( \ + opj_tcd_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_t * l_tcp = 00; \ + opj_cp_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 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 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 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 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 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 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 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 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 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 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 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 true; \ +} \ + +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 -void tcd_malloc_encode(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp, int curtileno) { - int tileno, compno, resno, bandno, precno, cblkno; - - tcd->image = image; - tcd->cp = cp; - tcd->tcd_image->tw = cp->tw; - tcd->tcd_image->th = cp->th; - tcd->tcd_image->tiles = (opj_tcd_tile_t *) opj_malloc(sizeof(opj_tcd_tile_t)); - - for (tileno = 0; tileno < 1; tileno++) { - opj_tcp_t *tcp = &cp->tcps[curtileno]; - int j; - - /* cfr p59 ISO/IEC FDIS15444-1 : 2000 (18 august 2000) */ - int p = curtileno % cp->tw; /* si numerotation matricielle .. */ - int q = curtileno / cp->tw; /* .. coordonnees de la tile (q,p) q pour ligne et p pour colonne */ - - /* opj_tcd_tile_t *tile=&tcd->tcd_image->tiles[tileno]; */ - opj_tcd_tile_t *tile = tcd->tcd_image->tiles; - - /* 4 borders of the tile rescale on the image if necessary */ - tile->x0 = int_max(cp->tx0 + p * cp->tdx, image->x0); - tile->y0 = int_max(cp->ty0 + q * cp->tdy, image->y0); - tile->x1 = int_min(cp->tx0 + (p + 1) * cp->tdx, image->x1); - tile->y1 = int_min(cp->ty0 + (q + 1) * cp->tdy, image->y1); - tile->numcomps = image->numcomps; - /* tile->PPT=image->PPT; */ - - /* Modification of the RATE >> */ - for (j = 0; j < tcp->numlayers; j++) { - tcp->rates[j] = tcp->rates[j] ? - cp->tp_on ? - (((float) (tile->numcomps - * (tile->x1 - tile->x0) - * (tile->y1 - tile->y0) - * image->comps[0].prec)) - /(tcp->rates[j] * 8 * image->comps[0].dx * image->comps[0].dy)) - (((tcd->cur_totnum_tp - 1) * 14 )/ tcp->numlayers) - : - ((float) (tile->numcomps - * (tile->x1 - tile->x0) - * (tile->y1 - tile->y0) - * image->comps[0].prec))/ - (tcp->rates[j] * 8 * image->comps[0].dx * image->comps[0].dy) - : 0; - - if (tcp->rates[j]) { - if (j && tcp->rates[j] < tcp->rates[j - 1] + 10) { - tcp->rates[j] = tcp->rates[j - 1] + 20; - } else { - if (!j && tcp->rates[j] < 30) - tcp->rates[j] = 30; - } - - if(j == (tcp->numlayers-1)){ - tcp->rates[j] = tcp->rates[j]- 2; - } - } +/** + * Allocates memory for an encoding code block. + */ +bool tcd_code_block_enc_allocate (opj_tcd_cblk_enc_t * p_code_block) +{ + if + (! p_code_block->data) + { + p_code_block->data = (OPJ_BYTE*) opj_malloc(8192+1); + if + (! p_code_block->data) + { + return false; } - /* << Modification of the RATE */ - - tile->comps = (opj_tcd_tilecomp_t *) opj_malloc(image->numcomps * sizeof(opj_tcd_tilecomp_t)); - for (compno = 0; compno < tile->numcomps; compno++) { - opj_tccp_t *tccp = &tcp->tccps[compno]; - - opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; - - /* border of each tile component (global) */ - tilec->x0 = int_ceildiv(tile->x0, image->comps[compno].dx); - tilec->y0 = int_ceildiv(tile->y0, image->comps[compno].dy); - tilec->x1 = int_ceildiv(tile->x1, image->comps[compno].dx); - tilec->y1 = int_ceildiv(tile->y1, image->comps[compno].dy); - - tilec->data = (int *) opj_aligned_malloc((tilec->x1 - tilec->x0) * (tilec->y1 - tilec->y0) * sizeof(int)); - tilec->numresolutions = tccp->numresolutions; - - tilec->resolutions = (opj_tcd_resolution_t *) opj_malloc(tilec->numresolutions * sizeof(opj_tcd_resolution_t)); - - for (resno = 0; resno < tilec->numresolutions; resno++) { - int pdx, pdy; - int levelno = tilec->numresolutions - 1 - resno; - int tlprcxstart, tlprcystart, brprcxend, brprcyend; - int tlcbgxstart, tlcbgystart, brcbgxend, brcbgyend; - int cbgwidthexpn, cbgheightexpn; - int cblkwidthexpn, cblkheightexpn; - - opj_tcd_resolution_t *res = &tilec->resolutions[resno]; - - /* border for each resolution level (global) */ - res->x0 = int_ceildivpow2(tilec->x0, levelno); - res->y0 = int_ceildivpow2(tilec->y0, levelno); - res->x1 = int_ceildivpow2(tilec->x1, levelno); - res->y1 = int_ceildivpow2(tilec->y1, levelno); - - res->numbands = resno == 0 ? 1 : 3; - /* p. 35, table A-23, ISO/IEC FDIS154444-1 : 2000 (18 august 2000) */ - if (tccp->csty & J2K_CCP_CSTY_PRT) { - pdx = tccp->prcw[resno]; - pdy = tccp->prch[resno]; - } else { - pdx = 15; - pdy = 15; - } - /* p. 64, B.6, ISO/IEC FDIS15444-1 : 2000 (18 august 2000) */ - tlprcxstart = int_floordivpow2(res->x0, pdx) << pdx; - tlprcystart = int_floordivpow2(res->y0, pdy) << pdy; - - brprcxend = int_ceildivpow2(res->x1, pdx) << pdx; - brprcyend = int_ceildivpow2(res->y1, pdy) << pdy; - - res->pw = (brprcxend - tlprcxstart) >> pdx; - res->ph = (brprcyend - tlprcystart) >> pdy; - - if (resno == 0) { - tlcbgxstart = tlprcxstart; - tlcbgystart = tlprcystart; - brcbgxend = brprcxend; - brcbgyend = brprcyend; - cbgwidthexpn = pdx; - cbgheightexpn = pdy; - } else { - tlcbgxstart = int_ceildivpow2(tlprcxstart, 1); - tlcbgystart = int_ceildivpow2(tlprcystart, 1); - brcbgxend = int_ceildivpow2(brprcxend, 1); - brcbgyend = int_ceildivpow2(brprcyend, 1); - cbgwidthexpn = pdx - 1; - cbgheightexpn = pdy - 1; - } - - cblkwidthexpn = int_min(tccp->cblkw, cbgwidthexpn); - cblkheightexpn = int_min(tccp->cblkh, cbgheightexpn); - - for (bandno = 0; bandno < res->numbands; bandno++) { - int x0b, y0b, i; - int gain, numbps; - opj_stepsize_t *ss = NULL; - - opj_tcd_band_t *band = &res->bands[bandno]; - - band->bandno = resno == 0 ? 0 : bandno + 1; - x0b = (band->bandno == 1) || (band->bandno == 3) ? 1 : 0; - y0b = (band->bandno == 2) || (band->bandno == 3) ? 1 : 0; - - if (band->bandno == 0) { - /* band border (global) */ - band->x0 = int_ceildivpow2(tilec->x0, levelno); - band->y0 = int_ceildivpow2(tilec->y0, levelno); - band->x1 = int_ceildivpow2(tilec->x1, levelno); - band->y1 = int_ceildivpow2(tilec->y1, levelno); - } else { - /* band border (global) */ - band->x0 = int_ceildivpow2(tilec->x0 - (1 << levelno) * x0b, levelno + 1); - band->y0 = int_ceildivpow2(tilec->y0 - (1 << levelno) * y0b, levelno + 1); - band->x1 = int_ceildivpow2(tilec->x1 - (1 << levelno) * x0b, levelno + 1); - band->y1 = int_ceildivpow2(tilec->y1 - (1 << levelno) * y0b, levelno + 1); - } - - ss = &tccp->stepsizes[resno == 0 ? 0 : 3 * (resno - 1) + bandno + 1]; - gain = tccp->qmfbid == 0 ? dwt_getgain_real(band->bandno) : dwt_getgain(band->bandno); - numbps = image->comps[compno].prec + gain; - - band->stepsize = (float)((1.0 + ss->mant / 2048.0) * pow(2.0, numbps - ss->expn)); - band->numbps = ss->expn + tccp->numgbits - 1; /* WHY -1 ? */ - - band->precincts = (opj_tcd_precinct_t *) opj_malloc(3 * res->pw * res->ph * sizeof(opj_tcd_precinct_t)); - - for (i = 0; i < res->pw * res->ph * 3; i++) { - band->precincts[i].imsbtree = NULL; - band->precincts[i].incltree = NULL; - } - - for (precno = 0; precno < res->pw * res->ph; precno++) { - int tlcblkxstart, tlcblkystart, brcblkxend, brcblkyend; - - int cbgxstart = tlcbgxstart + (precno % res->pw) * (1 << cbgwidthexpn); - int cbgystart = tlcbgystart + (precno / res->pw) * (1 << cbgheightexpn); - int cbgxend = cbgxstart + (1 << cbgwidthexpn); - int cbgyend = cbgystart + (1 << cbgheightexpn); - - opj_tcd_precinct_t *prc = &band->precincts[precno]; - - /* precinct size (global) */ - prc->x0 = int_max(cbgxstart, band->x0); - prc->y0 = int_max(cbgystart, band->y0); - prc->x1 = int_min(cbgxend, band->x1); - prc->y1 = int_min(cbgyend, band->y1); - - tlcblkxstart = int_floordivpow2(prc->x0, cblkwidthexpn) << cblkwidthexpn; - tlcblkystart = int_floordivpow2(prc->y0, cblkheightexpn) << cblkheightexpn; - brcblkxend = int_ceildivpow2(prc->x1, cblkwidthexpn) << cblkwidthexpn; - brcblkyend = int_ceildivpow2(prc->y1, cblkheightexpn) << cblkheightexpn; - prc->cw = (brcblkxend - tlcblkxstart) >> cblkwidthexpn; - prc->ch = (brcblkyend - tlcblkystart) >> cblkheightexpn; - - prc->cblks.enc = (opj_tcd_cblk_enc_t*) opj_calloc((prc->cw * prc->ch), sizeof(opj_tcd_cblk_enc_t)); - prc->incltree = tgt_create(prc->cw, prc->ch); - prc->imsbtree = tgt_create(prc->cw, prc->ch); - - for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { - int cblkxstart = tlcblkxstart + (cblkno % prc->cw) * (1 << cblkwidthexpn); - int cblkystart = tlcblkystart + (cblkno / prc->cw) * (1 << cblkheightexpn); - int cblkxend = cblkxstart + (1 << cblkwidthexpn); - int cblkyend = cblkystart + (1 << cblkheightexpn); - - opj_tcd_cblk_enc_t* cblk = &prc->cblks.enc[cblkno]; - - /* code-block size (global) */ - cblk->x0 = int_max(cblkxstart, prc->x0); - cblk->y0 = int_max(cblkystart, prc->y0); - cblk->x1 = int_min(cblkxend, prc->x1); - cblk->y1 = int_min(cblkyend, prc->y1); - cblk->data = (unsigned char*) opj_calloc(8192+2, sizeof(unsigned char)); - /* FIXME: mqc_init_enc and mqc_byteout underrun the buffer if we don't do this. Why? */ - cblk->data += 2; - cblk->layers = (opj_tcd_layer_t*) opj_calloc(100, sizeof(opj_tcd_layer_t)); - cblk->passes = (opj_tcd_pass_t*) opj_calloc(100, sizeof(opj_tcd_pass_t)); - } - } - } - } + p_code_block->data+=1; + /* no memset since data */ + p_code_block->layers = (opj_tcd_layer_t*) opj_malloc(100 * sizeof(opj_tcd_layer_t)); + if + (! p_code_block->layers) + { + return false; + } + p_code_block->passes = (opj_tcd_pass_t*) opj_malloc(100 * sizeof(opj_tcd_pass_t)); + if + (! p_code_block->passes) + { + return false; } } - - /* tcd_dump(stdout, tcd, &tcd->tcd_image); */ + memset(p_code_block->layers,0,100 * sizeof(opj_tcd_layer_t)); + memset(p_code_block->passes,0,100 * sizeof(opj_tcd_pass_t)); + return true; } -void tcd_free_encode(opj_tcd_t *tcd) { - int tileno, compno, resno, bandno, precno, cblkno; - - for (tileno = 0; tileno < 1; tileno++) { - opj_tcd_tile_t *tile = tcd->tcd_image->tiles; - - for (compno = 0; compno < tile->numcomps; compno++) { - opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; - - for (resno = 0; resno < tilec->numresolutions; resno++) { - opj_tcd_resolution_t *res = &tilec->resolutions[resno]; - - for (bandno = 0; bandno < res->numbands; bandno++) { - opj_tcd_band_t *band = &res->bands[bandno]; - - for (precno = 0; precno < res->pw * res->ph; precno++) { - opj_tcd_precinct_t *prc = &band->precincts[precno]; - - if (prc->incltree != NULL) { - tgt_destroy(prc->incltree); - prc->incltree = NULL; - } - if (prc->imsbtree != NULL) { - tgt_destroy(prc->imsbtree); - prc->imsbtree = NULL; - } - for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { - opj_free(prc->cblks.enc[cblkno].data - 2); - opj_free(prc->cblks.enc[cblkno].layers); - opj_free(prc->cblks.enc[cblkno].passes); - } - opj_free(prc->cblks.enc); - } /* for (precno */ - opj_free(band->precincts); - band->precincts = NULL; - } /* for (bandno */ - } /* for (resno */ - opj_free(tilec->resolutions); - tilec->resolutions = NULL; - } /* for (compno */ - opj_free(tile->comps); - tile->comps = NULL; - } /* for (tileno */ - opj_free(tcd->tcd_image->tiles); - tcd->tcd_image->tiles = NULL; +/** + * Allocates memory for a decoding code block. + */ +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 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 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 true; } -void tcd_init_encode(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp, int curtileno) { - int tileno, compno, resno, bandno, precno, cblkno; - - for (tileno = 0; tileno < 1; tileno++) { - opj_tcp_t *tcp = &cp->tcps[curtileno]; - int j; - /* cfr p59 ISO/IEC FDIS15444-1 : 2000 (18 august 2000) */ - int p = curtileno % cp->tw; - int q = curtileno / cp->tw; - - opj_tcd_tile_t *tile = tcd->tcd_image->tiles; - - /* 4 borders of the tile rescale on the image if necessary */ - tile->x0 = int_max(cp->tx0 + p * cp->tdx, image->x0); - tile->y0 = int_max(cp->ty0 + q * cp->tdy, image->y0); - tile->x1 = int_min(cp->tx0 + (p + 1) * cp->tdx, image->x1); - tile->y1 = int_min(cp->ty0 + (q + 1) * cp->tdy, image->y1); - - tile->numcomps = image->numcomps; - /* tile->PPT=image->PPT; */ - - /* Modification of the RATE >> */ - for (j = 0; j < tcp->numlayers; j++) { - tcp->rates[j] = tcp->rates[j] ? - cp->tp_on ? - (((float) (tile->numcomps - * (tile->x1 - tile->x0) - * (tile->y1 - tile->y0) - * image->comps[0].prec)) - /(tcp->rates[j] * 8 * image->comps[0].dx * image->comps[0].dy)) - (((tcd->cur_totnum_tp - 1) * 14 )/ tcp->numlayers) - : - ((float) (tile->numcomps - * (tile->x1 - tile->x0) - * (tile->y1 - tile->y0) - * image->comps[0].prec))/ - (tcp->rates[j] * 8 * image->comps[0].dx * image->comps[0].dy) - : 0; - - if (tcp->rates[j]) { - if (j && tcp->rates[j] < tcp->rates[j - 1] + 10) { - tcp->rates[j] = tcp->rates[j - 1] + 20; - } else { - if (!j && tcp->rates[j] < 30) - tcp->rates[j] = 30; - } +/** + * Deallocates the encoding data of the given precinct. + */ +void tcd_code_block_enc_deallocate (opj_tcd_precinct_t * p_precinct) +{ + OPJ_UINT32 cblkno , l_nb_code_blocks; + + opj_tcd_cblk_enc_t * l_code_block = p_precinct->cblks.enc; + if + (l_code_block) + { + l_nb_code_blocks = p_precinct->block_size / sizeof(opj_tcd_cblk_enc_t); + for + (cblkno = 0; cblkno < l_nb_code_blocks; ++cblkno) + { + if + (l_code_block->data) + { + opj_free(l_code_block->data-1); + l_code_block->data = 00; + } + if + (l_code_block->layers) + { + opj_free(l_code_block->layers ); + l_code_block->layers = 00; } + if + (l_code_block->passes) + { + opj_free(l_code_block->passes ); + l_code_block->passes = 00; + } + ++l_code_block; } - /* << Modification of the RATE */ - - /* tile->comps=(opj_tcd_tilecomp_t*)opj_realloc(tile->comps,image->numcomps*sizeof(opj_tcd_tilecomp_t)); */ - for (compno = 0; compno < tile->numcomps; compno++) { - opj_tccp_t *tccp = &tcp->tccps[compno]; - - opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; - - /* border of each tile component (global) */ - tilec->x0 = int_ceildiv(tile->x0, image->comps[compno].dx); - tilec->y0 = int_ceildiv(tile->y0, image->comps[compno].dy); - tilec->x1 = int_ceildiv(tile->x1, image->comps[compno].dx); - tilec->y1 = int_ceildiv(tile->y1, image->comps[compno].dy); - - tilec->data = (int *) opj_aligned_malloc((tilec->x1 - tilec->x0) * (tilec->y1 - tilec->y0) * sizeof(int)); - tilec->numresolutions = tccp->numresolutions; - /* tilec->resolutions=(opj_tcd_resolution_t*)opj_realloc(tilec->resolutions,tilec->numresolutions*sizeof(opj_tcd_resolution_t)); */ - for (resno = 0; resno < tilec->numresolutions; resno++) { - int pdx, pdy; - - int levelno = tilec->numresolutions - 1 - resno; - int tlprcxstart, tlprcystart, brprcxend, brprcyend; - int tlcbgxstart, tlcbgystart, brcbgxend, brcbgyend; - int cbgwidthexpn, cbgheightexpn; - int cblkwidthexpn, cblkheightexpn; - - opj_tcd_resolution_t *res = &tilec->resolutions[resno]; - - /* border for each resolution level (global) */ - res->x0 = int_ceildivpow2(tilec->x0, levelno); - res->y0 = int_ceildivpow2(tilec->y0, levelno); - res->x1 = int_ceildivpow2(tilec->x1, levelno); - res->y1 = int_ceildivpow2(tilec->y1, levelno); - res->numbands = resno == 0 ? 1 : 3; - - /* p. 35, table A-23, ISO/IEC FDIS154444-1 : 2000 (18 august 2000) */ - if (tccp->csty & J2K_CCP_CSTY_PRT) { - pdx = tccp->prcw[resno]; - pdy = tccp->prch[resno]; - } else { - pdx = 15; - pdy = 15; - } - /* p. 64, B.6, ISO/IEC FDIS15444-1 : 2000 (18 august 2000) */ - tlprcxstart = int_floordivpow2(res->x0, pdx) << pdx; - tlprcystart = int_floordivpow2(res->y0, pdy) << pdy; - brprcxend = int_ceildivpow2(res->x1, pdx) << pdx; - brprcyend = int_ceildivpow2(res->y1, pdy) << pdy; - - res->pw = (brprcxend - tlprcxstart) >> pdx; - res->ph = (brprcyend - tlprcystart) >> pdy; - - if (resno == 0) { - tlcbgxstart = tlprcxstart; - tlcbgystart = tlprcystart; - brcbgxend = brprcxend; - brcbgyend = brprcyend; - cbgwidthexpn = pdx; - cbgheightexpn = pdy; - } else { - tlcbgxstart = int_ceildivpow2(tlprcxstart, 1); - tlcbgystart = int_ceildivpow2(tlprcystart, 1); - brcbgxend = int_ceildivpow2(brprcxend, 1); - brcbgyend = int_ceildivpow2(brprcyend, 1); - cbgwidthexpn = pdx - 1; - cbgheightexpn = pdy - 1; - } - - cblkwidthexpn = int_min(tccp->cblkw, cbgwidthexpn); - cblkheightexpn = int_min(tccp->cblkh, cbgheightexpn); - - for (bandno = 0; bandno < res->numbands; bandno++) { - int x0b, y0b; - int gain, numbps; - opj_stepsize_t *ss = NULL; - - opj_tcd_band_t *band = &res->bands[bandno]; - - band->bandno = resno == 0 ? 0 : bandno + 1; - x0b = (band->bandno == 1) || (band->bandno == 3) ? 1 : 0; - y0b = (band->bandno == 2) || (band->bandno == 3) ? 1 : 0; - - if (band->bandno == 0) { - /* band border */ - band->x0 = int_ceildivpow2(tilec->x0, levelno); - band->y0 = int_ceildivpow2(tilec->y0, levelno); - band->x1 = int_ceildivpow2(tilec->x1, levelno); - band->y1 = int_ceildivpow2(tilec->y1, levelno); - } else { - band->x0 = int_ceildivpow2(tilec->x0 - (1 << levelno) * x0b, levelno + 1); - band->y0 = int_ceildivpow2(tilec->y0 - (1 << levelno) * y0b, levelno + 1); - band->x1 = int_ceildivpow2(tilec->x1 - (1 << levelno) * x0b, levelno + 1); - band->y1 = int_ceildivpow2(tilec->y1 - (1 << levelno) * y0b, levelno + 1); - } - - ss = &tccp->stepsizes[resno == 0 ? 0 : 3 * (resno - 1) + bandno + 1]; - gain = tccp->qmfbid == 0 ? dwt_getgain_real(band->bandno) : dwt_getgain(band->bandno); - numbps = image->comps[compno].prec + gain; - band->stepsize = (float)((1.0 + ss->mant / 2048.0) * pow(2.0, numbps - ss->expn)); - band->numbps = ss->expn + tccp->numgbits - 1; /* WHY -1 ? */ - - for (precno = 0; precno < res->pw * res->ph; precno++) { - int tlcblkxstart, tlcblkystart, brcblkxend, brcblkyend; - - int cbgxstart = tlcbgxstart + (precno % res->pw) * (1 << cbgwidthexpn); - int cbgystart = tlcbgystart + (precno / res->pw) * (1 << cbgheightexpn); - int cbgxend = cbgxstart + (1 << cbgwidthexpn); - int cbgyend = cbgystart + (1 << cbgheightexpn); - - opj_tcd_precinct_t *prc = &band->precincts[precno]; - - /* precinct size (global) */ - prc->x0 = int_max(cbgxstart, band->x0); - prc->y0 = int_max(cbgystart, band->y0); - prc->x1 = int_min(cbgxend, band->x1); - prc->y1 = int_min(cbgyend, band->y1); - - tlcblkxstart = int_floordivpow2(prc->x0, cblkwidthexpn) << cblkwidthexpn; - tlcblkystart = int_floordivpow2(prc->y0, cblkheightexpn) << cblkheightexpn; - brcblkxend = int_ceildivpow2(prc->x1, cblkwidthexpn) << cblkwidthexpn; - brcblkyend = int_ceildivpow2(prc->y1, cblkheightexpn) << cblkheightexpn; - prc->cw = (brcblkxend - tlcblkxstart) >> cblkwidthexpn; - prc->ch = (brcblkyend - tlcblkystart) >> cblkheightexpn; - - opj_free(prc->cblks.enc); - prc->cblks.enc = (opj_tcd_cblk_enc_t*) opj_calloc(prc->cw * prc->ch, sizeof(opj_tcd_cblk_enc_t)); - - if (prc->incltree != NULL) { - tgt_destroy(prc->incltree); - } - if (prc->imsbtree != NULL) { - tgt_destroy(prc->imsbtree); - } - - prc->incltree = tgt_create(prc->cw, prc->ch); - prc->imsbtree = tgt_create(prc->cw, prc->ch); - - for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { - int cblkxstart = tlcblkxstart + (cblkno % prc->cw) * (1 << cblkwidthexpn); - int cblkystart = tlcblkystart + (cblkno / prc->cw) * (1 << cblkheightexpn); - int cblkxend = cblkxstart + (1 << cblkwidthexpn); - int cblkyend = cblkystart + (1 << cblkheightexpn); - - opj_tcd_cblk_enc_t* cblk = &prc->cblks.enc[cblkno]; - - /* code-block size (global) */ - cblk->x0 = int_max(cblkxstart, prc->x0); - cblk->y0 = int_max(cblkystart, prc->y0); - cblk->x1 = int_min(cblkxend, prc->x1); - cblk->y1 = int_min(cblkyend, prc->y1); - cblk->data = (unsigned char*) opj_calloc(8192+2, sizeof(unsigned char)); - /* FIXME: mqc_init_enc and mqc_byteout underrun the buffer if we don't do this. Why? */ - cblk->data += 2; - cblk->layers = (opj_tcd_layer_t*) opj_calloc(100, sizeof(opj_tcd_layer_t)); - cblk->passes = (opj_tcd_pass_t*) opj_calloc(100, sizeof(opj_tcd_pass_t)); - } - } /* precno */ - } /* bandno */ - } /* resno */ - } /* compno */ - } /* tileno */ - - /* tcd_dump(stdout, tcd, &tcd->tcd_image); */ -} - -void tcd_malloc_decode(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp) { - int i, j, tileno, p, q; - unsigned int x0 = 0, y0 = 0, x1 = 0, y1 = 0, w, h; - - tcd->image = image; - tcd->tcd_image->tw = cp->tw; - tcd->tcd_image->th = cp->th; - tcd->tcd_image->tiles = (opj_tcd_tile_t *) opj_malloc(cp->tw * cp->th * sizeof(opj_tcd_tile_t)); - - /* - Allocate place to store the decoded data = final image - Place limited by the tile really present in the codestream - */ - - for (j = 0; j < cp->tileno_size; j++) { - opj_tcd_tile_t *tile; - - tileno = cp->tileno[j]; - tile = &(tcd->tcd_image->tiles[cp->tileno[tileno]]); - tile->numcomps = image->numcomps; - tile->comps = (opj_tcd_tilecomp_t*) opj_calloc(image->numcomps, sizeof(opj_tcd_tilecomp_t)); + opj_free(p_precinct->cblks.enc); + p_precinct->cblks.enc = 00; } +} - for (i = 0; i < image->numcomps; i++) { - for (j = 0; j < cp->tileno_size; j++) { - opj_tcd_tile_t *tile; - opj_tcd_tilecomp_t *tilec; - - /* cfr p59 ISO/IEC FDIS15444-1 : 2000 (18 august 2000) */ - - tileno = cp->tileno[j]; - - tile = &(tcd->tcd_image->tiles[cp->tileno[tileno]]); - tilec = &tile->comps[i]; - - p = tileno % cp->tw; /* si numerotation matricielle .. */ - q = tileno / cp->tw; /* .. coordonnees de la tile (q,p) q pour ligne et p pour colonne */ - - /* 4 borders of the tile rescale on the image if necessary */ - tile->x0 = int_max(cp->tx0 + p * cp->tdx, image->x0); - tile->y0 = int_max(cp->ty0 + q * cp->tdy, image->y0); - tile->x1 = int_min(cp->tx0 + (p + 1) * cp->tdx, image->x1); - tile->y1 = int_min(cp->ty0 + (q + 1) * cp->tdy, image->y1); - - tilec->x0 = int_ceildiv(tile->x0, image->comps[i].dx); - tilec->y0 = int_ceildiv(tile->y0, image->comps[i].dy); - tilec->x1 = int_ceildiv(tile->x1, image->comps[i].dx); - tilec->y1 = int_ceildiv(tile->y1, image->comps[i].dy); - - x0 = j == 0 ? tilec->x0 : int_min(x0, (unsigned int) tilec->x0); - y0 = j == 0 ? tilec->y0 : int_min(y0, (unsigned int) tilec->x0); - x1 = j == 0 ? tilec->x1 : int_max(x1, (unsigned int) tilec->x1); - y1 = j == 0 ? tilec->y1 : int_max(y1, (unsigned int) tilec->y1); +/** + * 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; } - - w = int_ceildivpow2(x1 - x0, image->comps[i].factor); - h = int_ceildivpow2(y1 - y0, image->comps[i].factor); - - image->comps[i].w = w; - image->comps[i].h = h; - image->comps[i].x0 = x0; - image->comps[i].y0 = y0; + opj_free(p_precinct->cblks.dec); + p_precinct->cblks.dec = 00; } } -void tcd_malloc_decode_tile(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp, int tileno, opj_codestream_info_t *cstr_info) { - int compno, resno, bandno, precno, cblkno; - opj_tcp_t *tcp; - opj_tcd_tile_t *tile; - - tcd->cp = cp; +void tcd_free_tile(opj_tcd_t *p_tcd) +{ + OPJ_UINT32 compno, resno, bandno, precno; + opj_tcd_tile_t *l_tile = 00; + opj_tcd_tilecomp_t *l_tile_comp = 00; + opj_tcd_resolution_t *l_res = 00; + opj_tcd_band_t *l_band = 00; + opj_tcd_precinct_t *l_precinct = 00; + OPJ_UINT32 l_nb_resolutions, l_nb_precincts; + void (* l_tcd_code_block_deallocate) (opj_tcd_precinct_t *) = 00; - tcp = &(cp->tcps[cp->tileno[tileno]]); - tile = &(tcd->tcd_image->tiles[cp->tileno[tileno]]); + if + (! p_tcd) + { + return; + } + if + (! p_tcd->tcd_image) + { + return; + } + if + (p_tcd->m_is_decoder) + { + l_tcd_code_block_deallocate = tcd_code_block_dec_deallocate; + } + else + { + l_tcd_code_block_deallocate = tcd_code_block_enc_deallocate; + } + - tileno = cp->tileno[tileno]; + l_tile = p_tcd->tcd_image->tiles; + if + (! l_tile) + { + return; + } + l_tile_comp = l_tile->comps; - for (compno = 0; compno < tile->numcomps; compno++) { - opj_tccp_t *tccp = &tcp->tccps[compno]; - opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; - - /* border of each tile component (global) */ - tilec->x0 = int_ceildiv(tile->x0, image->comps[compno].dx); - tilec->y0 = int_ceildiv(tile->y0, image->comps[compno].dy); - tilec->x1 = int_ceildiv(tile->x1, image->comps[compno].dx); - tilec->y1 = int_ceildiv(tile->y1, image->comps[compno].dy); - - tilec->numresolutions = tccp->numresolutions; - tilec->resolutions = (opj_tcd_resolution_t *) opj_malloc(tilec->numresolutions * sizeof(opj_tcd_resolution_t)); - - for (resno = 0; resno < tilec->numresolutions; resno++) { - int pdx, pdy; - int levelno = tilec->numresolutions - 1 - resno; - int tlprcxstart, tlprcystart, brprcxend, brprcyend; - int tlcbgxstart, tlcbgystart, brcbgxend, brcbgyend; - int cbgwidthexpn, cbgheightexpn; - int cblkwidthexpn, cblkheightexpn; - - opj_tcd_resolution_t *res = &tilec->resolutions[resno]; - - /* border for each resolution level (global) */ - res->x0 = int_ceildivpow2(tilec->x0, levelno); - res->y0 = int_ceildivpow2(tilec->y0, levelno); - res->x1 = int_ceildivpow2(tilec->x1, levelno); - res->y1 = int_ceildivpow2(tilec->y1, levelno); - res->numbands = resno == 0 ? 1 : 3; - - /* p. 35, table A-23, ISO/IEC FDIS154444-1 : 2000 (18 august 2000) */ - if (tccp->csty & J2K_CCP_CSTY_PRT) { - pdx = tccp->prcw[resno]; - pdy = tccp->prch[resno]; - } else { - pdx = 15; - pdy = 15; - } - - /* p. 64, B.6, ISO/IEC FDIS15444-1 : 2000 (18 august 2000) */ - tlprcxstart = int_floordivpow2(res->x0, pdx) << pdx; - tlprcystart = int_floordivpow2(res->y0, pdy) << pdy; - brprcxend = int_ceildivpow2(res->x1, pdx) << pdx; - brprcyend = int_ceildivpow2(res->y1, pdy) << pdy; - - res->pw = (res->x0 == res->x1) ? 0 : ((brprcxend - tlprcxstart) >> pdx); - res->ph = (res->y0 == res->y1) ? 0 : ((brprcyend - tlprcystart) >> pdy); - - if (resno == 0) { - tlcbgxstart = tlprcxstart; - tlcbgystart = tlprcystart; - brcbgxend = brprcxend; - brcbgyend = brprcyend; - cbgwidthexpn = pdx; - cbgheightexpn = pdy; - } else { - tlcbgxstart = int_ceildivpow2(tlprcxstart, 1); - tlcbgystart = int_ceildivpow2(tlprcystart, 1); - brcbgxend = int_ceildivpow2(brprcxend, 1); - brcbgyend = int_ceildivpow2(brprcyend, 1); - cbgwidthexpn = pdx - 1; - cbgheightexpn = pdy - 1; - } - - cblkwidthexpn = int_min(tccp->cblkw, cbgwidthexpn); - cblkheightexpn = int_min(tccp->cblkh, cbgheightexpn); - - for (bandno = 0; bandno < res->numbands; bandno++) { - int x0b, y0b; - int gain, numbps; - opj_stepsize_t *ss = NULL; - - opj_tcd_band_t *band = &res->bands[bandno]; - band->bandno = resno == 0 ? 0 : bandno + 1; - x0b = (band->bandno == 1) || (band->bandno == 3) ? 1 : 0; - y0b = (band->bandno == 2) || (band->bandno == 3) ? 1 : 0; - - if (band->bandno == 0) { - /* band border (global) */ - band->x0 = int_ceildivpow2(tilec->x0, levelno); - band->y0 = int_ceildivpow2(tilec->y0, levelno); - band->x1 = int_ceildivpow2(tilec->x1, levelno); - band->y1 = int_ceildivpow2(tilec->y1, levelno); - } else { - /* band border (global) */ - band->x0 = int_ceildivpow2(tilec->x0 - (1 << levelno) * x0b, levelno + 1); - band->y0 = int_ceildivpow2(tilec->y0 - (1 << levelno) * y0b, levelno + 1); - band->x1 = int_ceildivpow2(tilec->x1 - (1 << levelno) * x0b, levelno + 1); - band->y1 = int_ceildivpow2(tilec->y1 - (1 << levelno) * y0b, levelno + 1); - } - - ss = &tccp->stepsizes[resno == 0 ? 0 : 3 * (resno - 1) + bandno + 1]; - gain = tccp->qmfbid == 0 ? dwt_getgain_real(band->bandno) : dwt_getgain(band->bandno); - numbps = image->comps[compno].prec + gain; - band->stepsize = (float)(((1.0 + ss->mant / 2048.0) * pow(2.0, numbps - ss->expn)) * 0.5); - band->numbps = ss->expn + tccp->numgbits - 1; /* WHY -1 ? */ - - band->precincts = (opj_tcd_precinct_t *) opj_malloc(res->pw * res->ph * sizeof(opj_tcd_precinct_t)); - - for (precno = 0; precno < res->pw * res->ph; precno++) { - int tlcblkxstart, tlcblkystart, brcblkxend, brcblkyend; - int cbgxstart = tlcbgxstart + (precno % res->pw) * (1 << cbgwidthexpn); - int cbgystart = tlcbgystart + (precno / res->pw) * (1 << cbgheightexpn); - int cbgxend = cbgxstart + (1 << cbgwidthexpn); - int cbgyend = cbgystart + (1 << cbgheightexpn); - - opj_tcd_precinct_t *prc = &band->precincts[precno]; - /* precinct size (global) */ - prc->x0 = int_max(cbgxstart, band->x0); - prc->y0 = int_max(cbgystart, band->y0); - prc->x1 = int_min(cbgxend, band->x1); - prc->y1 = int_min(cbgyend, band->y1); - - tlcblkxstart = int_floordivpow2(prc->x0, cblkwidthexpn) << cblkwidthexpn; - tlcblkystart = int_floordivpow2(prc->y0, cblkheightexpn) << cblkheightexpn; - brcblkxend = int_ceildivpow2(prc->x1, cblkwidthexpn) << cblkwidthexpn; - brcblkyend = int_ceildivpow2(prc->y1, cblkheightexpn) << cblkheightexpn; - prc->cw = (brcblkxend - tlcblkxstart) >> cblkwidthexpn; - prc->ch = (brcblkyend - tlcblkystart) >> cblkheightexpn; - - prc->cblks.dec = (opj_tcd_cblk_dec_t*) opj_malloc(prc->cw * prc->ch * sizeof(opj_tcd_cblk_dec_t)); - - prc->incltree = tgt_create(prc->cw, prc->ch); - prc->imsbtree = tgt_create(prc->cw, prc->ch); - - for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { - int cblkxstart = tlcblkxstart + (cblkno % prc->cw) * (1 << cblkwidthexpn); - int cblkystart = tlcblkystart + (cblkno / prc->cw) * (1 << cblkheightexpn); - int cblkxend = cblkxstart + (1 << cblkwidthexpn); - int cblkyend = cblkystart + (1 << cblkheightexpn); - - opj_tcd_cblk_dec_t* cblk = &prc->cblks.dec[cblkno]; - cblk->data = NULL; - cblk->segs = NULL; - /* code-block size (global) */ - cblk->x0 = int_max(cblkxstart, prc->x0); - cblk->y0 = int_max(cblkystart, prc->y0); - cblk->x1 = int_min(cblkxend, prc->x1); - cblk->y1 = int_min(cblkyend, prc->y1); - cblk->numsegs = 0; + 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; } - } /* precno */ - } /* bandno */ - } /* resno */ - } /* compno */ - /* tcd_dump(stdout, tcd, &tcd->tcd_image); */ + ++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; +} + +bool tcd_init( + opj_tcd_t *p_tcd, + opj_image_t * p_image, + opj_cp_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 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 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 true; } -void tcd_makelayer_fixed(opj_tcd_t *tcd, int layno, int final) { - int compno, resno, bandno, precno, cblkno; - int value; /*, matrice[tcd_tcp->numlayers][tcd_tile->comps[0].numresolutions][3]; */ - int matrice[10][10][3]; - int i, j, k; +void tcd_makelayer_fixed(opj_tcd_t *tcd, OPJ_UINT32 layno, OPJ_UINT32 final) { + OPJ_UINT32 compno, resno, bandno, precno, cblkno; + OPJ_INT32 value; /*, matrice[tcd_tcp->numlayers][tcd_tile->comps[0].numresolutions][3]; */ + OPJ_INT32 matrice[10][10][3]; + OPJ_UINT32 i, j, k; opj_cp_t *cp = tcd->cp; - opj_tcd_tile_t *tcd_tile = tcd->tcd_tile; + opj_tcd_tile_t *tcd_tile = tcd->tcd_image->tiles; opj_tcp_t *tcd_tcp = tcd->tcp; - /*matrice=(int*)opj_malloc(tcd_tcp->numlayers*tcd_tile->comps[0].numresolutions*3*sizeof(int)); */ - for (compno = 0; compno < tcd_tile->numcomps; compno++) { opj_tcd_tilecomp_t *tilec = &tcd_tile->comps[compno]; for (i = 0; i < tcd_tcp->numlayers; i++) { for (j = 0; j < tilec->numresolutions; j++) { for (k = 0; k < 3; k++) { matrice[i][j][k] = - (int) (cp->matrice[i * tilec->numresolutions * 3 + j * 3 + k] - * (float) (tcd->image->comps[compno].prec / 16.0)); + (OPJ_INT32) (cp->m_specific_param.m_enc.m_matrice[i * tilec->numresolutions * 3 + j * 3 + k] + * (OPJ_FLOAT32) (tcd->image->comps[compno].prec / 16.0)); } } } @@ -864,8 +781,8 @@ void tcd_makelayer_fixed(opj_tcd_t *tcd, int layno, int final) { for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { opj_tcd_cblk_enc_t *cblk = &prc->cblks.enc[cblkno]; opj_tcd_layer_t *layer = &cblk->layers[layno]; - int n; - int imsb = tcd->image->comps[compno].prec - cblk->numbps; /* number of bit-plan equal to zero */ + OPJ_UINT32 n; + OPJ_INT32 imsb = tcd->image->comps[compno].prec - cblk->numbps; /* number of bit-plan equal to zero */ /* Correction of the matrix of coefficient to include the IMSB information */ if (layno == 0) { value = matrice[layno][resno][bandno]; @@ -921,16 +838,17 @@ void tcd_makelayer_fixed(opj_tcd_t *tcd, int layno, int final) { } void tcd_rateallocate_fixed(opj_tcd_t *tcd) { - int layno; + OPJ_UINT32 layno; for (layno = 0; layno < tcd->tcp->numlayers; layno++) { tcd_makelayer_fixed(tcd, layno, 1); } } -void tcd_makelayer(opj_tcd_t *tcd, int layno, double thresh, int final) { - int compno, resno, bandno, precno, cblkno, passno; +void tcd_makelayer(opj_tcd_t *tcd, OPJ_UINT32 layno, OPJ_FLOAT64 thresh, OPJ_UINT32 final) { + OPJ_UINT32 compno, resno, bandno, precno, cblkno; + OPJ_UINT32 passno; - opj_tcd_tile_t *tcd_tile = tcd->tcd_tile; + opj_tcd_tile_t *tcd_tile = tcd->tcd_image->tiles; tcd_tile->distolayer[layno] = 0; /* fixed_quality */ @@ -946,14 +864,14 @@ void tcd_makelayer(opj_tcd_t *tcd, int layno, double thresh, int final) { opj_tcd_cblk_enc_t *cblk = &prc->cblks.enc[cblkno]; opj_tcd_layer_t *layer = &cblk->layers[layno]; - int n; + OPJ_UINT32 n; if (layno == 0) { cblk->numpassesinlayers = 0; } n = cblk->numpassesinlayers; for (passno = cblk->numpassesinlayers; passno < cblk->totalpasses; passno++) { - int dr; - double dd; + OPJ_INT32 dr; + OPJ_FLOAT64 dd; opj_tcd_pass_t *pass = &cblk->passes[passno]; if (n == 0) { dr = pass->rate; @@ -997,15 +915,16 @@ void tcd_makelayer(opj_tcd_t *tcd, int layno, double thresh, int final) { } } -bool tcd_rateallocate(opj_tcd_t *tcd, unsigned char *dest, int len, opj_codestream_info_t *cstr_info) { - int compno, resno, bandno, precno, cblkno, passno, layno; - double min, max; - double cumdisto[100]; /* fixed_quality */ - const double K = 1; /* 1.1; fixed_quality */ - double maxSE = 0; +bool tcd_rateallocate(opj_tcd_t *tcd, OPJ_BYTE *dest, OPJ_UINT32 * p_data_written, OPJ_UINT32 len, opj_codestream_info_t *cstr_info) { + OPJ_UINT32 compno, resno, bandno, precno, cblkno, layno; + OPJ_UINT32 passno; + OPJ_FLOAT64 min, max; + OPJ_FLOAT64 cumdisto[100]; /* fixed_quality */ + const OPJ_FLOAT64 K = 1; /* 1.1; fixed_quality */ + OPJ_FLOAT64 maxSE = 0; opj_cp_t *cp = tcd->cp; - opj_tcd_tile_t *tcd_tile = tcd->tcd_tile; + opj_tcd_tile_t *tcd_tile = tcd->tcd_image->tiles; opj_tcp_t *tcd_tcp = tcd->tcp; min = DBL_MAX; @@ -1031,8 +950,8 @@ bool tcd_rateallocate(opj_tcd_t *tcd, unsigned char *dest, int len, opj_codestre for (passno = 0; passno < cblk->totalpasses; passno++) { opj_tcd_pass_t *pass = &cblk->passes[passno]; - int dr; - double dd, rdslope; + OPJ_INT32 dr; + OPJ_FLOAT64 dd, rdslope; if (passno == 0) { dr = pass->rate; dd = pass->distortiondec; @@ -1060,9 +979,9 @@ bool tcd_rateallocate(opj_tcd_t *tcd, unsigned char *dest, int len, opj_codestre } /* bandno */ } /* resno */ - maxSE += (((double)(1 << tcd->image->comps[compno].prec) - 1.0) - * ((double)(1 << tcd->image->comps[compno].prec) -1.0)) - * ((double)(tilec->numpix)); + maxSE += (((OPJ_FLOAT64)(1 << tcd->image->comps[compno].prec) - 1.0) + * ((OPJ_FLOAT64)(1 << tcd->image->comps[compno].prec) -1.0)) + * ((OPJ_FLOAT64)(tilec->numpix)); } /* compno */ /* index file */ @@ -1070,44 +989,53 @@ bool tcd_rateallocate(opj_tcd_t *tcd, unsigned char *dest, int len, opj_codestre opj_tile_info_t *tile_info = &cstr_info->tile[tcd->tcd_tileno]; tile_info->numpix = tcd_tile->numpix; tile_info->distotile = tcd_tile->distotile; - tile_info->thresh = (double *) opj_malloc(tcd_tcp->numlayers * sizeof(double)); + tile_info->thresh = (OPJ_FLOAT64 *) opj_malloc(tcd_tcp->numlayers * sizeof(OPJ_FLOAT64)); } for (layno = 0; layno < tcd_tcp->numlayers; layno++) { - double lo = min; - double hi = max; - int success = 0; - int maxlen = tcd_tcp->rates[layno] ? int_min(((int) ceil(tcd_tcp->rates[layno])), len) : len; - double goodthresh = 0; - double stable_thresh = 0; - int i; - double distotarget; /* fixed_quality */ + OPJ_FLOAT64 lo = min; + OPJ_FLOAT64 hi = max; + bool success = false; + OPJ_UINT32 maxlen = tcd_tcp->rates[layno] ? uint_min(((OPJ_UINT32) ceil(tcd_tcp->rates[layno])), len) : len; + OPJ_FLOAT64 goodthresh = 0; + OPJ_FLOAT64 stable_thresh = 0; + OPJ_UINT32 i; + OPJ_FLOAT64 distotarget; /* fixed_quality */ /* fixed_quality */ - distotarget = tcd_tile->distotile - ((K * maxSE) / pow((float)10, tcd_tcp->distoratio[layno] / 10)); + distotarget = tcd_tile->distotile - ((K * maxSE) / pow((OPJ_FLOAT32)10, tcd_tcp->distoratio[layno] / 10)); /* Don't try to find an optimal threshold but rather take everything not included yet, if -r xx,yy,zz,0 (disto_alloc == 1 and rates == 0) -q xx,yy,zz,0 (fixed_quality == 1 and distoratio == 0) ==> possible to have some lossy layers and the last layer for sure lossless */ - if ( ((cp->disto_alloc==1) && (tcd_tcp->rates[layno]>0)) || ((cp->fixed_quality==1) && (tcd_tcp->distoratio[layno]>0))) { - opj_t2_t *t2 = t2_create(tcd->cinfo, tcd->image, cp); - double thresh = 0; + if ( ((cp->m_specific_param.m_enc.m_disto_alloc==1) && (tcd_tcp->rates[layno]>0)) || ((cp->m_specific_param.m_enc.m_fixed_quality==1) && (tcd_tcp->distoratio[layno]>0))) { + opj_t2_t *t2 = t2_create(tcd->image, cp); + OPJ_FLOAT64 thresh = 0; + if + (t2 == 00) + { + return false; + } - for (i = 0; i < 32; i++) { - int l = 0; - double distoachieved = 0; /* fixed_quality */ + for + (i = 0; i < 32; ++i) + { + OPJ_FLOAT64 distoachieved = 0; /* fixed_quality */ thresh = (lo + hi) / 2; tcd_makelayer(tcd, layno, thresh, 0); - if (cp->fixed_quality) { /* fixed_quality */ - if(cp->cinema){ - l = t2_encode_packets(t2,tcd->tcd_tileno, tcd_tile, layno + 1, dest, maxlen, cstr_info,tcd->cur_tp_num,tcd->tp_pos,tcd->cur_pino,THRESH_CALC, tcd->cur_totnum_tp); - if (l == -999) { + if (cp->m_specific_param.m_enc.m_fixed_quality) { /* fixed_quality */ + if(cp->m_specific_param.m_enc.m_cinema){ + if + (! t2_encode_packets(t2,tcd->tcd_tileno, tcd_tile, layno + 1, dest, p_data_written, maxlen, cstr_info,tcd->cur_tp_num,tcd->tp_pos,tcd->cur_pino,THRESH_CALC)) + { lo = thresh; continue; - }else{ + } + else + { distoachieved = layno == 0 ? tcd_tile->distolayer[0] : cumdisto[layno - 1] + tcd_tile->distolayer[layno]; if (distoachieved < distotarget) { @@ -1129,10 +1057,11 @@ bool tcd_rateallocate(opj_tcd_t *tcd, unsigned char *dest, int len, opj_codestre lo = thresh; } } else { - l = t2_encode_packets(t2, tcd->tcd_tileno, tcd_tile, layno + 1, dest, maxlen, cstr_info,tcd->cur_tp_num,tcd->tp_pos,tcd->cur_pino,THRESH_CALC, tcd->cur_totnum_tp); - /* TODO: what to do with l ??? seek / tell ??? */ - /* opj_event_msg(tcd->cinfo, EVT_INFO, "rate alloc: len=%d, max=%d\n", l, maxlen); */ - if (l == -999) { + if + (! t2_encode_packets(t2, tcd->tcd_tileno, tcd_tile, layno + 1, dest,p_data_written, maxlen, cstr_info,tcd->cur_tp_num,tcd->tp_pos,tcd->cur_pino,THRESH_CALC)) + { + /* TODO: what to do with l ??? seek / tell ??? */ + /* opj_event_msg(tcd->cinfo, EVT_INFO, "rate alloc: len=%d, max=%d\n", l, maxlen); */ lo = thresh; continue; } @@ -1140,11 +1069,11 @@ bool tcd_rateallocate(opj_tcd_t *tcd, unsigned char *dest, int len, opj_codestre stable_thresh = thresh; } } - success = 1; + success = true; goodthresh = stable_thresh == 0? thresh : stable_thresh; t2_destroy(t2); } else { - success = 1; + success = true; goodthresh = min; } @@ -1164,353 +1093,1029 @@ bool tcd_rateallocate(opj_tcd_t *tcd, unsigned char *dest, int len, opj_codestre return true; } -int tcd_encode_tile(opj_tcd_t *tcd, int tileno, unsigned char *dest, int len, opj_codestream_info_t *cstr_info) { - int compno; - int l, i, numpacks = 0; - opj_tcd_tile_t *tile = NULL; - opj_tcp_t *tcd_tcp = NULL; - opj_cp_t *cp = NULL; - - opj_tcp_t *tcp = &tcd->cp->tcps[0]; - opj_tccp_t *tccp = &tcp->tccps[0]; - opj_image_t *image = tcd->image; - - opj_t1_t *t1 = NULL; /* T1 component */ - opj_t2_t *t2 = NULL; /* T2 component */ +OPJ_UINT32 tcd_get_encoded_tile_size ( + opj_tcd_t *p_tcd + ) +{ + OPJ_UINT32 i,l_data_size = 0; + opj_image_comp_t * l_img_comp = 00; + opj_tcd_tilecomp_t * l_tilec = 00; + OPJ_UINT32 l_size_comp, l_remaining; + + l_tilec = p_tcd->tcd_image->tiles->comps; + l_img_comp = p_tcd->image->comps; + for + (i=0;i<p_tcd->image->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_data_size += l_size_comp * (l_tilec->x1 - l_tilec->x0) * (l_tilec->y1 - l_tilec->y0); + ++l_img_comp; + ++l_tilec; + } + return l_data_size; +} - tcd->tcd_tileno = tileno; - tcd->tcd_tile = tcd->tcd_image->tiles; - tcd->tcp = &tcd->cp->tcps[tileno]; +bool tcd_copy_tile_data ( + opj_tcd_t *p_tcd, + OPJ_BYTE * p_src, + OPJ_UINT32 p_src_length + ) +{ + OPJ_UINT32 i,j,l_data_size = 0; + opj_image_comp_t * l_img_comp = 00; + opj_tcd_tilecomp_t * l_tilec = 00; + OPJ_UINT32 l_size_comp, l_remaining; + OPJ_UINT32 l_nb_elem; + + l_data_size = tcd_get_encoded_tile_size(p_tcd); + if + (l_data_size != p_src_length) + { + return false; + } + l_tilec = p_tcd->tcd_image->tiles->comps; + l_img_comp = p_tcd->image->comps; + for + (i=0;i<p_tcd->image->numcomps;++i) + { + l_size_comp = l_img_comp->prec >> 3; /*(/ 8)*/ + l_remaining = l_img_comp->prec & 7; /* (%8) */ + l_nb_elem = (l_tilec->x1 - l_tilec->x0) * (l_tilec->y1 - l_tilec->y0); + if + (l_remaining) + { + ++l_size_comp; + } + if + (l_size_comp == 3) + { + l_size_comp = 4; + } + switch + (l_size_comp) + { + case 1: + { + OPJ_CHAR * l_src_ptr = (OPJ_CHAR *) p_src; + OPJ_INT32 * l_dest_ptr = l_tilec->data; + if + (l_img_comp->sgnd) + { + for + (j=0;j<l_nb_elem;++j) + { + *(l_dest_ptr++) = (OPJ_INT32) (*(l_src_ptr++)); + } + } + else + { + for + (j=0;j<l_nb_elem;++j) + { + *(l_dest_ptr++) = (*(l_src_ptr++))&0xff; + } + } + p_src = (OPJ_BYTE*) l_src_ptr; + } + break; + case 2: + { + OPJ_INT32 * l_dest_ptr = l_tilec->data; + OPJ_INT16 * l_src_ptr = (OPJ_INT16 *) p_src; + if + (l_img_comp->sgnd) + { + for + (j=0;j<l_nb_elem;++j) + { + *(l_dest_ptr++) = (OPJ_INT32) (*(l_src_ptr++)); + } + } + else + { + for + (j=0;j<l_nb_elem;++j) + { + *(l_dest_ptr++) = (*(l_src_ptr++))&0xffff; + } + + } + p_src = (OPJ_BYTE*) l_src_ptr; + } + break; + case 4: + { + OPJ_INT32 * l_src_ptr = (OPJ_INT32 *) p_src; + OPJ_INT32 * l_dest_ptr = l_tilec->data; + for + (j=0;j<l_nb_elem;++j) + { + *(l_dest_ptr++) = (OPJ_INT32) (*(l_src_ptr++)); + } + p_src = (OPJ_BYTE*) l_src_ptr; + } + break; + } + ++l_img_comp; + ++l_tilec; + } + return true; +} - tile = tcd->tcd_tile; - tcd_tcp = tcd->tcp; - cp = tcd->cp; +bool tcd_update_tile_data ( + opj_tcd_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 false; + } - if(tcd->cur_tp_num == 0){ - tcd->encoding_time = opj_clock(); /* time needed to encode a tile */ - /* INDEX >> "Precinct_nb_X et Precinct_nb_Y" */ - if(cstr_info) { - opj_tcd_tilecomp_t *tilec_idx = &tile->comps[0]; /* based on component 0 */ - for (i = 0; i < tilec_idx->numresolutions; i++) { - opj_tcd_resolution_t *res_idx = &tilec_idx->resolutions[i]; - - cstr_info->tile[tileno].pw[i] = res_idx->pw; - cstr_info->tile[tileno].ph[i] = res_idx->ph; - - numpacks += res_idx->pw * res_idx->ph; - - cstr_info->tile[tileno].pdx[i] = tccp->prcw[i]; - cstr_info->tile[tileno].pdy[i] = tccp->prch[i]; - } - cstr_info->tile[tileno].packet = (opj_packet_info_t*) opj_calloc(cstr_info->numcomps * cstr_info->numlayers * numpacks, sizeof(opj_packet_info_t)); + l_tilec = p_tcd->tcd_image->tiles->comps; + l_img_comp = p_tcd->image->comps; + for + (i=0;i<p_tcd->image->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; } - /* << INDEX */ - - /*---------------TILE-------------------*/ - - for (compno = 0; compno < tile->numcomps; compno++) { - int x, y; - - int adjust = image->comps[compno].sgnd ? 0 : 1 << (image->comps[compno].prec - 1); - int offset_x = int_ceildiv(image->x0, image->comps[compno].dx); - int offset_y = int_ceildiv(image->y0, image->comps[compno].dy); - - opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; - int tw = tilec->x1 - tilec->x0; - int w = int_ceildiv(image->x1 - image->x0, image->comps[compno].dx); - - /* extract tile data */ - - if (tcd_tcp->tccps[compno].qmfbid == 1) { - for (y = tilec->y0; y < tilec->y1; y++) { - /* start of the src tile scanline */ - int *data = &image->comps[compno].data[(tilec->x0 - offset_x) + (y - offset_y) * w]; - /* start of the dst tile scanline */ - int *tile_data = &tilec->data[(y - tilec->y0) * tw]; - for (x = tilec->x0; x < tilec->x1; x++) { - *tile_data++ = *data++ - adjust; + 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;j<l_height;++j) + { + for + (k=0;k<l_width;++k) + { + *(l_dest_ptr++) = (OPJ_CHAR) (*(l_src_ptr++)); + } + l_src_ptr += l_stride; + } + } + else + { + for + (j=0;j<l_height;++j) + { + for + (k=0;k<l_width;++k) + { + *(l_dest_ptr++) = (OPJ_BYTE) ((*(l_src_ptr++))&0xff); + } + l_src_ptr += l_stride; + } } + p_dest = (OPJ_BYTE *)l_dest_ptr; + } - } else if (tcd_tcp->tccps[compno].qmfbid == 0) { - for (y = tilec->y0; y < tilec->y1; y++) { - /* start of the src tile scanline */ - int *data = &image->comps[compno].data[(tilec->x0 - offset_x) + (y - offset_y) * w]; - /* start of the dst tile scanline */ - int *tile_data = &tilec->data[(y - tilec->y0) * tw]; - for (x = tilec->x0; x < tilec->x1; x++) { - *tile_data++ = (*data++ - adjust) << 11; + break; + case 2: + { + const OPJ_INT32 * l_src_ptr = l_tilec->data; + OPJ_INT16 * l_dest_ptr = (OPJ_INT16 *) p_dest; + if + (l_img_comp->sgnd) + { + for + (j=0;j<l_height;++j) + { + for + (k=0;k<l_width;++k) + { + *(l_dest_ptr++) = (OPJ_INT16) (*(l_src_ptr++)); + } + l_src_ptr += l_stride; + } } - + else + { + for + (j=0;j<l_height;++j) + { + for + (k=0;k<l_width;++k) + { + *(l_dest_ptr++) = (OPJ_UINT16) ((*(l_src_ptr++))&0xffff); + } + l_src_ptr += l_stride; + } + } + p_dest = (OPJ_BYTE*) l_dest_ptr; + } + break; + case 4: + { + OPJ_INT32 * l_dest_ptr = (OPJ_INT32 *) p_dest; + OPJ_INT32 * l_src_ptr = l_tilec->data; + for + (j=0;j<l_height;++j) + { + for + (k=0;k<l_width;++k) + { + *(l_dest_ptr++) = (*(l_src_ptr++)); + } + l_src_ptr += l_stride; + } + p_dest = (OPJ_BYTE*) l_dest_ptr; } + break; + } + ++l_img_comp; + ++l_tilec; + } + return true; +} + +OPJ_UINT32 tcd_get_decoded_tile_size ( + opj_tcd_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;i<p_tcd->image->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; +} + +bool tcd_dc_level_shift_encode ( + opj_tcd_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_tcp_t * l_tcp = 00; + opj_tcd_tile_t * l_tile; + OPJ_UINT32 l_nb_elem,i; + OPJ_INT32 * l_current_ptr; + + 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_current_ptr = l_tile_comp->data; + l_nb_elem = (l_tile_comp->x1 - l_tile_comp->x0) * (l_tile_comp->y1 - l_tile_comp->y0); + if + (l_tccp->qmfbid == 1) + { + for + (i = 0; i < l_nb_elem; ++i) + { + *l_current_ptr -= l_tccp->m_dc_level_shift ; + ++l_current_ptr; } } - - /*----------------MCT-------------------*/ - if (tcd_tcp->mct) { - int samples = (tile->comps[0].x1 - tile->comps[0].x0) * (tile->comps[0].y1 - tile->comps[0].y0); - if (tcd_tcp->tccps[0].qmfbid == 0) { - mct_encode_real(tile->comps[0].data, tile->comps[1].data, tile->comps[2].data, samples); - } else { - mct_encode(tile->comps[0].data, tile->comps[1].data, tile->comps[2].data, samples); + else + { + for + (i = 0; i < l_nb_elem; ++i) + { + *l_current_ptr = (*l_current_ptr - l_tccp->m_dc_level_shift) << 11 ; + ++l_current_ptr; } } - - /*----------------DWT---------------------*/ - - for (compno = 0; compno < tile->numcomps; compno++) { - opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; - if (tcd_tcp->tccps[compno].qmfbid == 1) { - dwt_encode(tilec); - } else if (tcd_tcp->tccps[compno].qmfbid == 0) { - dwt_encode_real(tilec); + ++l_img_comp; + ++l_tccp; + ++l_tile_comp; + } + return true; +} + +bool tcd_mct_encode ( + opj_tcd_t *p_tcd + ) +{ + opj_tcd_tile_t * l_tile = p_tcd->tcd_image->tiles; + opj_tcd_tilecomp_t * l_tile_comp = p_tcd->tcd_image->tiles->comps; + OPJ_UINT32 samples = (l_tile_comp->x1 - l_tile_comp->x0) * (l_tile_comp->y1 - l_tile_comp->y0); + OPJ_UINT32 i; + OPJ_BYTE ** l_data = 00; + opj_tcp_t * l_tcp = p_tcd->tcp; + if + (!p_tcd->tcp->mct) + { + return true; + } + + if + (p_tcd->tcp->mct == 2) + { + if + (! p_tcd->tcp->m_mct_coding_matrix) + { + return true; + } + l_data = (OPJ_BYTE **) opj_malloc(l_tile->numcomps*sizeof(OPJ_BYTE*)); + if + (! l_data) + { + return false; + } + for + (i=0;i<l_tile->numcomps;++i) + { + l_data[i] = (OPJ_BYTE*) l_tile_comp->data; + ++l_tile_comp; + } + if + (! mct_encode_custom(// MCT data + (OPJ_BYTE*) p_tcd->tcp->m_mct_coding_matrix, + // size of components + 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 false; + } + opj_free(l_data); + } + else if (l_tcp->tccps->qmfbid == 0) + { + mct_encode_real(l_tile->comps[0].data, l_tile->comps[1].data, l_tile->comps[2].data, samples); + } + else + { + mct_encode(l_tile->comps[0].data, l_tile->comps[1].data, l_tile->comps[2].data, samples); + } + return true; +} + +bool tcd_dwt_encode ( + opj_tcd_t *p_tcd + ) +{ + opj_tcd_tile_t * l_tile = p_tcd->tcd_image->tiles; + opj_tcd_tilecomp_t * l_tile_comp = p_tcd->tcd_image->tiles->comps; + opj_tccp_t * l_tccp = p_tcd->tcp->tccps; + OPJ_UINT32 compno; + + + for + (compno = 0; compno < l_tile->numcomps; ++compno) + { + if + (l_tccp->qmfbid == 1) + { + if + (! dwt_encode(l_tile_comp)) + { + return false; + } + } + else if + (l_tccp->qmfbid == 0) + { + if + (! dwt_encode_real(l_tile_comp)) + { + return false; } } - - /*------------------TIER1-----------------*/ - t1 = t1_create(tcd->cinfo); - t1_encode_cblks(t1, tile, tcd_tcp); - t1_destroy(t1); - - /*-----------RATE-ALLOCATE------------------*/ - - /* INDEX */ - if(cstr_info) { - cstr_info->index_write = 0; + ++l_tile_comp; + ++l_tccp; + } + return true; +} + +bool tcd_t1_encode ( + opj_tcd_t *p_tcd + ) +{ + opj_t1_t * l_t1; + const OPJ_FLOAT64 * l_mct_norms; + opj_tcp_t * l_tcp = p_tcd->tcp; + + l_t1 = t1_create(); + if + (l_t1 == 00) + { + return false; + } + if + (l_tcp->mct == 1) + { + // irreversible encoding + if + (l_tcp->tccps->qmfbid == 0) + { + l_mct_norms = get_mct_norms_real(); } - if (cp->disto_alloc || cp->fixed_quality) { /* fixed_quality */ - /* Normal Rate/distortion allocation */ - tcd_rateallocate(tcd, dest, len, cstr_info); - } else { - /* Fixed layer allocation */ - tcd_rateallocate_fixed(tcd); + else + { + l_mct_norms = get_mct_norms(); } } - /*--------------TIER2------------------*/ + else + { + l_mct_norms = (const OPJ_FLOAT64 *) (l_tcp->mct_norms); + } + + if + (! t1_encode_cblks(l_t1, p_tcd->tcd_image->tiles , l_tcp, l_mct_norms)) + { + t1_destroy(l_t1); + return false; + } + t1_destroy(l_t1); + return true; +} - /* INDEX */ - if(cstr_info) { - cstr_info->index_write = 1; +bool tcd_t2_encode ( + opj_tcd_t *p_tcd, + OPJ_BYTE * p_dest_data, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 p_max_dest_size, + opj_codestream_info_t *p_cstr_info + ) +{ + opj_t2_t * l_t2; + + l_t2 = t2_create(p_tcd->image, p_tcd->cp); + if + (l_t2 == 00) + { + return false; } - t2 = t2_create(tcd->cinfo, image, cp); - l = t2_encode_packets(t2,tileno, tile, tcd_tcp->numlayers, dest, len, cstr_info,tcd->tp_num,tcd->tp_pos,tcd->cur_pino,FINAL_PASS,tcd->cur_totnum_tp); - t2_destroy(t2); + if + (! t2_encode_packets( + l_t2, + p_tcd->tcd_tileno, + p_tcd->tcd_image->tiles, + p_tcd->tcp->numlayers, + p_dest_data, + p_data_written, + p_max_dest_size, + p_cstr_info, + p_tcd->tp_num, + p_tcd->tp_pos, + p_tcd->cur_pino, + FINAL_PASS)) + { + t2_destroy(l_t2); + return false; + } + t2_destroy(l_t2); /*---------------CLEAN-------------------*/ + return true; +} - - if(tcd->cur_tp_num == tcd->cur_totnum_tp - 1){ - tcd->encoding_time = opj_clock() - tcd->encoding_time; - opj_event_msg(tcd->cinfo, EVT_INFO, "- tile encoded in %f s\n", tcd->encoding_time); - - /* cleaning memory */ - for (compno = 0; compno < tile->numcomps; compno++) { - opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; - opj_aligned_free(tilec->data); +bool tcd_rate_allocate_encode( + opj_tcd_t *p_tcd, + OPJ_BYTE * p_dest_data, + OPJ_UINT32 p_max_dest_size, + opj_codestream_info_t *p_cstr_info + ) +{ + opj_cp_t * l_cp = p_tcd->cp; + OPJ_UINT32 l_nb_written = 0; + + if + (p_cstr_info) + { + p_cstr_info->index_write = 0; + } + if + (l_cp->m_specific_param.m_enc.m_disto_alloc|| l_cp->m_specific_param.m_enc.m_fixed_quality) + { /* fixed_quality */ + /* Normal Rate/distortion allocation */ + if + (! tcd_rateallocate(p_tcd, p_dest_data,&l_nb_written, p_max_dest_size, p_cstr_info)) + { + return false; } } - - return l; + else + { + /* Fixed layer allocation */ + tcd_rateallocate_fixed(p_tcd); + } + return true; } -bool tcd_decode_tile(opj_tcd_t *tcd, unsigned char *src, int len, int tileno, opj_codestream_info_t *cstr_info) { - int l; - int compno; - int eof = 0; - double tile_time, t1_time, dwt_time; - opj_tcd_tile_t *tile = NULL; - - opj_t1_t *t1 = NULL; /* T1 component */ - opj_t2_t *t2 = NULL; /* T2 component */ - - tcd->tcd_tileno = tileno; - tcd->tcd_tile = &(tcd->tcd_image->tiles[tileno]); - tcd->tcp = &(tcd->cp->tcps[tileno]); - tile = tcd->tcd_tile; - - tile_time = opj_clock(); /* time needed to decode a tile */ - opj_event_msg(tcd->cinfo, EVT_INFO, "tile %d of %d\n", tileno + 1, tcd->cp->tw * tcd->cp->th); +bool tcd_t2_decode ( + opj_tcd_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_t * l_t2; + + l_t2 = t2_create(p_tcd->image, p_tcd->cp); + if + (l_t2 == 00) + { + return false; + } - /* INDEX >> */ - if(cstr_info) { - int resno, compno, numprec = 0; - for (compno = 0; compno < cstr_info->numcomps; compno++) { - opj_tcp_t *tcp = &tcd->cp->tcps[0]; - opj_tccp_t *tccp = &tcp->tccps[compno]; - opj_tcd_tilecomp_t *tilec_idx = &tile->comps[compno]; - for (resno = 0; resno < tilec_idx->numresolutions; resno++) { - opj_tcd_resolution_t *res_idx = &tilec_idx->resolutions[resno]; - cstr_info->tile[tileno].pw[resno] = res_idx->pw; - cstr_info->tile[tileno].ph[resno] = res_idx->ph; - numprec += res_idx->pw * res_idx->ph; - if (tccp->csty & J2K_CP_CSTY_PRT) { - cstr_info->tile[tileno].pdx[resno] = tccp->prcw[resno]; - cstr_info->tile[tileno].pdy[resno] = tccp->prch[resno]; - } - else { - cstr_info->tile[tileno].pdx[resno] = 15; - cstr_info->tile[tileno].pdx[resno] = 15; - } - } - } - cstr_info->tile[tileno].packet = (opj_packet_info_t *) opj_malloc(cstr_info->numlayers * numprec * sizeof(opj_packet_info_t)); - cstr_info->packno = 0; + if + (! t2_decode_packets( + 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(l_t2); + return false; } - /* << INDEX */ + t2_destroy(l_t2); - /*--------------TIER2------------------*/ + /*---------------CLEAN-------------------*/ + return true; +} + +bool tcd_t1_decode ( + opj_tcd_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; - t2 = t2_create(tcd->cinfo, tcd->image, tcd->cp); - l = t2_decode_packets(t2, src, len, tileno, tile, cstr_info); - t2_destroy(t2); - if (l == -999) { - eof = 1; - opj_event_msg(tcd->cinfo, EVT_ERROR, "tcd_decode: incomplete bistream\n"); + l_t1 = t1_create(); + if + (l_t1 == 00) + { + return false; } - - /*------------------TIER1-----------------*/ - - t1_time = opj_clock(); /* time needed to decode a tile */ - t1 = t1_create(tcd->cinfo); - for (compno = 0; compno < tile->numcomps; ++compno) { - opj_tcd_tilecomp_t* tilec = &tile->comps[compno]; + for + (compno = 0; compno < l_tile->numcomps; ++compno) + { /* The +3 is headroom required by the vectorized DWT */ - tilec->data = (int*) opj_aligned_malloc((((tilec->x1 - tilec->x0) * (tilec->y1 - tilec->y0))+3) * sizeof(int)); - t1_decode_cblks(t1, tilec, &tcd->tcp->tccps[compno]); + t1_decode_cblks(l_t1, l_tile_comp, l_tccp); + ++l_tile_comp; + ++l_tccp; } - t1_destroy(t1); - t1_time = opj_clock() - t1_time; - opj_event_msg(tcd->cinfo, EVT_INFO, "- tiers-1 took %f s\n", t1_time); - - /*----------------DWT---------------------*/ - - dwt_time = opj_clock(); /* time needed to decode a tile */ - for (compno = 0; compno < tile->numcomps; compno++) { - opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; - int numres2decode; + t1_destroy(l_t1); + return true; +} +bool tcd_dwt_decode ( + opj_tcd_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) { - opj_event_msg(tcd->cinfo, EVT_ERROR, "Error decoding tile. The number of resolutions to remove [%d+1] is higher than the number " - " of resolutions in the original codestream [%d]\nModify the cp_reduce parameter.\n", tcd->cp->reduce, tile->comps[compno].numresolutions); + if (tcd->image->comps[compno].resno_decoded < 0) + { return false; } } - numres2decode = tcd->image->comps[compno].resno_decoded + 1; if(numres2decode > 0){ - if (tcd->tcp->tccps[compno].qmfbid == 1) { - dwt_decode(tilec, numres2decode); - } else { - dwt_decode_real(tilec, numres2decode); + */ + if + (l_tccp->qmfbid == 1) + { + if + (! dwt_decode(l_tile_comp, l_img_comp->resno_decoded+1)) + { + return false; + } + } + else + { + if + (! dwt_decode_real(l_tile_comp, l_img_comp->resno_decoded+1)) + { + return false; } } + ++l_tile_comp; + ++l_img_comp; + ++l_tccp; } - dwt_time = opj_clock() - dwt_time; - opj_event_msg(tcd->cinfo, EVT_INFO, "- dwt took %f s\n", dwt_time); - - /*----------------MCT-------------------*/ - - if (tcd->tcp->mct) { - int n = (tile->comps[0].x1 - tile->comps[0].x0) * (tile->comps[0].y1 - tile->comps[0].y0); - if (tcd->tcp->tccps[0].qmfbid == 1) { + return true; +} +bool tcd_mct_decode ( + opj_tcd_t *p_tcd + ) +{ + opj_tcd_tile_t * l_tile = p_tcd->tcd_image->tiles; + opj_tcp_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 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 true; + } + l_data = (OPJ_BYTE **) opj_malloc(l_tile->numcomps*sizeof(OPJ_BYTE*)); + if + (! l_data) + { + return false; + } + for + (i=0;i<l_tile->numcomps;++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 false; + } + opj_free(l_data); + } + else + { + if + (l_tcp->tccps->qmfbid == 1) + { mct_decode( - tile->comps[0].data, - tile->comps[1].data, - tile->comps[2].data, - n); - } else { + l_tile->comps[0].data, + l_tile->comps[1].data, + l_tile->comps[2].data, + l_samples); + } + else + { mct_decode_real( - (float*)tile->comps[0].data, - (float*)tile->comps[1].data, - (float*)tile->comps[2].data, - n); + (float*)l_tile->comps[0].data, + (float*)l_tile->comps[1].data, + (float*)l_tile->comps[2].data, + l_samples); } } + return true; +} - /*---------------TILE-------------------*/ - - for (compno = 0; compno < tile->numcomps; ++compno) { - opj_tcd_tilecomp_t* tilec = &tile->comps[compno]; - opj_image_comp_t* imagec = &tcd->image->comps[compno]; - opj_tcd_resolution_t* res = &tilec->resolutions[imagec->resno_decoded]; - int adjust = imagec->sgnd ? 0 : 1 << (imagec->prec - 1); - int min = imagec->sgnd ? -(1 << (imagec->prec - 1)) : 0; - int max = imagec->sgnd ? (1 << (imagec->prec - 1)) - 1 : (1 << imagec->prec) - 1; - - int tw = tilec->x1 - tilec->x0; - int w = imagec->w; - - int offset_x = int_ceildivpow2(imagec->x0, imagec->factor); - int offset_y = int_ceildivpow2(imagec->y0, imagec->factor); - - int i, j; - if(!imagec->data){ - imagec->data = (int*) opj_malloc(imagec->w * imagec->h * sizeof(int)); +bool tcd_dc_level_shift_decode ( + opj_tcd_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_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; } - if(tcd->tcp->tccps[compno].qmfbid == 1) { - for(j = res->y0; j < res->y1; ++j) { - for(i = res->x0; i < res->x1; ++i) { - int v = tilec->data[i - res->x0 + (j - res->y0) * tw]; - v += adjust; - imagec->data[(i - offset_x) + (j - offset_y) * w] = int_clamp(v, min, max); + l_current_ptr = l_tile_comp->data; + if + (l_tccp->qmfbid == 1) + { + for + (j=0;j<l_height;++j) + { + for + (i = 0; i < l_width; ++i) + { + *l_current_ptr = int_clamp(*l_current_ptr + l_tccp->m_dc_level_shift, l_min, l_max); + ++l_current_ptr; } + l_current_ptr += l_stride; } - }else{ - for(j = res->y0; j < res->y1; ++j) { - for(i = res->x0; i < res->x1; ++i) { - float tmp = ((float*)tilec->data)[i - res->x0 + (j - res->y0) * tw]; - int v = lrintf(tmp); - v += adjust; - imagec->data[(i - offset_x) + (j - offset_y) * w] = int_clamp(v, min, max); + } + else + { + for + (j=0;j<l_height;++j) + { + for + (i = 0; i < l_width; ++i) + { + OPJ_FLOAT32 l_value = *((OPJ_FLOAT32 *) l_current_ptr); + *l_current_ptr = int_clamp(lrintf(l_value) + l_tccp->m_dc_level_shift, l_min, l_max); ; + ++l_current_ptr; } + l_current_ptr += l_stride; } } - opj_aligned_free(tilec->data); + ++l_img_comp; + ++l_tccp; + ++l_tile_comp; } + return true; +} + +bool tcd_encode_tile( + opj_tcd_t *p_tcd, + OPJ_UINT32 p_tile_no, + OPJ_BYTE *p_dest, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 p_max_length, + opj_codestream_info_t *p_cstr_info) +{ + + if + (p_tcd->cur_tp_num == 0) + { + p_tcd->tcd_tileno = p_tile_no; + p_tcd->tcp = &p_tcd->cp->tcps[p_tile_no]; + /* INDEX >> "Precinct_nb_X et Precinct_nb_Y" */ + if(p_cstr_info) + { + OPJ_UINT32 l_num_packs = 0; + OPJ_UINT32 i; + opj_tcd_tilecomp_t *l_tilec_idx = &p_tcd->tcd_image->tiles->comps[0]; /* based on component 0 */ + opj_tccp_t *l_tccp = p_tcd->tcp->tccps; /* based on component 0 */ + for (i = 0; i < l_tilec_idx->numresolutions; i++) { + opj_tcd_resolution_t *l_res_idx = &l_tilec_idx->resolutions[i]; + + p_cstr_info->tile[p_tile_no].pw[i] = l_res_idx->pw; + p_cstr_info->tile[p_tile_no].ph[i] = l_res_idx->ph; + + l_num_packs += l_res_idx->pw * l_res_idx->ph; + p_cstr_info->tile[p_tile_no].pdx[i] = l_tccp->prcw[i]; + p_cstr_info->tile[p_tile_no].pdy[i] = l_tccp->prch[i]; + } + p_cstr_info->tile[p_tile_no].packet = (opj_packet_info_t*) opj_calloc(p_cstr_info->numcomps * p_cstr_info->numlayers * l_num_packs, sizeof(opj_packet_info_t)); + } + /* << INDEX */ + _ProfStart(PGROUP_DC_SHIFT); + /*---------------TILE-------------------*/ + if + (! tcd_dc_level_shift_encode(p_tcd)) + { + return false; + } + _ProfStop(PGROUP_DC_SHIFT); + + _ProfStart(PGROUP_MCT); + if + (! tcd_mct_encode(p_tcd)) + { + return false; + } + _ProfStop(PGROUP_MCT); + + _ProfStart(PGROUP_DWT); + if + (! tcd_dwt_encode(p_tcd)) + { + return false; + } + _ProfStop(PGROUP_DWT); + + _ProfStart(PGROUP_T1); + if + (! tcd_t1_encode(p_tcd)) + { + return false; + } + _ProfStop(PGROUP_T1); - tile_time = opj_clock() - tile_time; /* time needed to decode a tile */ - opj_event_msg(tcd->cinfo, EVT_INFO, "- tile decoded in %f s\n", tile_time); + _ProfStart(PGROUP_RATE); + if + (! tcd_rate_allocate_encode(p_tcd,p_dest,p_max_length,p_cstr_info)) + { + return false; + } + _ProfStop(PGROUP_RATE); + + } + /*--------------TIER2------------------*/ - if (eof) { + /* INDEX */ + if + (p_cstr_info) + { + p_cstr_info->index_write = 1; + } + _ProfStart(PGROUP_T2); + if + (! tcd_t2_encode(p_tcd,p_dest,p_data_written,p_max_length,p_cstr_info)) + { return false; } - + _ProfStop(PGROUP_T2); + /*---------------CLEAN-------------------*/ return true; } -void tcd_free_decode(opj_tcd_t *tcd) { - opj_tcd_image_t *tcd_image = tcd->tcd_image; - opj_free(tcd_image->tiles); -} - -void tcd_free_decode_tile(opj_tcd_t *tcd, int tileno) { - int compno,resno,bandno,precno; - - opj_tcd_image_t *tcd_image = tcd->tcd_image; - - opj_tcd_tile_t *tile = &tcd_image->tiles[tileno]; - for (compno = 0; compno < tile->numcomps; compno++) { - opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; - for (resno = 0; resno < tilec->numresolutions; resno++) { - opj_tcd_resolution_t *res = &tilec->resolutions[resno]; - for (bandno = 0; bandno < res->numbands; bandno++) { - opj_tcd_band_t *band = &res->bands[bandno]; - for (precno = 0; precno < res->ph * res->pw; precno++) { - opj_tcd_precinct_t *prec = &band->precincts[precno]; - if (prec->imsbtree != NULL) tgt_destroy(prec->imsbtree); - if (prec->incltree != NULL) tgt_destroy(prec->incltree); - } - opj_free(band->precincts); +bool tcd_decode_tile( + opj_tcd_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_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]; } } - opj_free(tilec->resolutions); + 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; } - opj_free(tile->comps); -} + /* << INDEX */ + + /*--------------TIER2------------------*/ + _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 false; + } + _ProfStop(PGROUP_T2); + + /*------------------TIER1-----------------*/ + + _ProfStart(PGROUP_T1); + if + (! tcd_t1_decode(p_tcd)) + { + return false; + } + _ProfStop(PGROUP_T1); + + /*----------------DWT---------------------*/ + _ProfStart(PGROUP_DWT); + if + (! tcd_dwt_decode(p_tcd)) + { + return false; + } + _ProfStop(PGROUP_DWT); + + /*----------------MCT-------------------*/ + _ProfStart(PGROUP_MCT); + if + (! tcd_mct_decode(p_tcd)) + { + return false; + } + _ProfStop(PGROUP_MCT); + _ProfStart(PGROUP_DC_SHIFT); + if + (! tcd_dc_level_shift_decode(p_tcd)) + { + return false; + } + _ProfStop(PGROUP_DC_SHIFT); + + /*---------------TILE-------------------*/ + return true; +} diff --git a/libopenjpeg/tcd.h b/libopenjpeg/tcd.h index f0ac5619..b18b682b 100644 --- a/libopenjpeg/tcd.h +++ b/libopenjpeg/tcd.h @@ -5,6 +5,7 @@ * Copyright (c) 2002-2003, Yannick Verschueren * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,167 +38,180 @@ The functions in TCD.C have for goal to encode or decode each tile independently from each other. The functions in TCD.C are used by some function in J2K.C. */ - +#include "openjpeg.h" /** @defgroup TCD TCD - Implementation of a tile coder/decoder */ /*@{*/ +struct opj_common_struct; +struct opj_codestream_info; +struct opj_image; +struct opj_tcp; +struct opj_cp; +struct opj_tgt_tree; /** 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; /** FIXME: documentation */ typedef struct opj_tcd_pass { - int rate; - double distortiondec; - int term, len; + OPJ_UINT32 rate; + OPJ_FLOAT64 distortiondec; + OPJ_UINT32 len; + OPJ_UINT32 term : 1; } opj_tcd_pass_t; /** FIXME: documentation */ typedef struct opj_tcd_layer { - int numpasses; /* Number of passes in the layer */ - int len; /* len of information */ - double disto; /* add for index (Cfr. Marcela) */ - unsigned char *data; /* data */ + OPJ_UINT32 numpasses; /* Number of passes in the layer */ + OPJ_UINT32 len; /* len of information */ + OPJ_FLOAT64 disto; /* add for index (Cfr. Marcela) */ + OPJ_BYTE *data; /* data */ } opj_tcd_layer_t; /** FIXME: documentation */ typedef struct opj_tcd_cblk_enc { - unsigned char* data; /* Data */ + OPJ_BYTE* data; /* Data */ opj_tcd_layer_t* layers; /* layer information */ opj_tcd_pass_t* passes; /* information about the passes */ - 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 numpasses; /* number of pass already done for the code-blocks */ - int numpassesinlayers; /* number of passes in the layer */ - int totalpasses; /* total number of passes */ + 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 numpasses; /* number of pass already done for the code-blocks */ + OPJ_UINT32 numpassesinlayers; /* number of passes in the layer */ + OPJ_UINT32 totalpasses; /* total number of passes */ } opj_tcd_cblk_enc_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 */ + 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_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; /** FIXME: documentation */ typedef struct opj_tcd_resolution { - int x0, y0, x1, y1; /* dimension of the resolution level : left upper corner (x0, y0) right low corner (x1,y1) */ - int pw, ph; - int numbands; /* number sub-band for the resolution level */ + OPJ_INT32 x0, y0, x1, y1; /* dimension of the resolution level : left upper corner (x0, y0) right low corner (x1,y1) */ + OPJ_UINT32 pw, ph; + OPJ_UINT32 numbands; /* number sub-band for the resolution level */ opj_tcd_band_t bands[3]; /* subband information */ } opj_tcd_resolution_t; /** 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 +{ + 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 */ typedef struct opj_tcd_tile { - int x0, y0, x1, y1; /* dimension of the tile : left upper corner (x0, y0) right low corner (x1,y1) */ - int numcomps; /* number of components in tile */ + OPJ_INT32 x0, y0, x1, y1; /* dimension of the tile : left upper corner (x0, y0) right low corner (x1,y1) */ + OPJ_UINT32 numcomps; /* number of components in tile */ opj_tcd_tilecomp_t *comps; /* Components information */ - int numpix; /* add fixed_quality */ - double distotile; /* add fixed_quality */ - double distolayer[100]; /* add fixed_quality */ + OPJ_INT32 numpix; /* add fixed_quality */ + OPJ_FLOAT64 distotile; /* add fixed_quality */ + OPJ_FLOAT64 distolayer[100]; /* add fixed_quality */ /** packet number */ - int packno; + OPJ_UINT32 packno; } opj_tcd_tile_t; /** FIXME: documentation */ -typedef struct opj_tcd_image { - int tw, th; /* number of tiles in width and heigth */ +typedef struct opj_tcd_image +{ opj_tcd_tile_t *tiles; /* Tiles information */ -} opj_tcd_image_t; +} +opj_tcd_image_t; /** Tile coder/decoder */ -typedef struct opj_tcd { +typedef struct opj_tcd +{ /** Position of the tilepart flag in Progression order*/ - int tp_pos; + OPJ_INT32 tp_pos; /** Tile part number*/ - int tp_num; + OPJ_UINT32 tp_num; /** Current tile part number*/ - int cur_tp_num; + OPJ_UINT32 cur_tp_num; /** Total number of tileparts of the current tile*/ - int cur_totnum_tp; + OPJ_UINT32 cur_totnum_tp; /** Current Packet iterator number */ - int cur_pino; - /** codec context */ - opj_common_ptr cinfo; - + OPJ_UINT32 cur_pino; /** info on each image tile */ - opj_tcd_image_t *tcd_image; + struct opj_tcd_image *tcd_image; /** image */ - opj_image_t *image; + struct opj_image *image; /** coding parameters */ - opj_cp_t *cp; - /** pointer to the current encoded/decoded tile */ - opj_tcd_tile_t *tcd_tile; + struct opj_cp *cp; /** coding/decoding parameters common to all tiles */ - opj_tcp_t *tcp; + struct opj_tcp *tcp; /** current encoded/decoded tile */ - int tcd_tileno; - /** Time taken to encode a tile*/ - double encoding_time; + OPJ_UINT32 tcd_tileno; + /** tell if the tcd is a decoder. */ + OPJ_UINT32 m_is_decoder : 1; } opj_tcd_t; /** @name Exported functions */ @@ -207,61 +221,86 @@ typedef struct opj_tcd { /** Dump the content of a tcd structure */ -void tcd_dump(FILE *fd, opj_tcd_t *tcd, opj_tcd_image_t *img); +//void tcd_dump(FILE *fd, opj_tcd_t *tcd, opj_tcd_image_t *img); /** Create a new TCD handle @param cinfo Codec context info @return Returns a new TCD handle if successful returns NULL otherwise */ -opj_tcd_t* tcd_create(opj_common_ptr cinfo); +opj_tcd_t* tcd_create(bool p_is_decoder); + /** Destroy a previously created TCD handle @param tcd TCD handle to destroy */ void tcd_destroy(opj_tcd_t *tcd); + + + + /** -Initialize the tile coder (allocate the memory) -@param tcd TCD handle -@param image Raw image -@param cp Coding parameters -@param curtileno Number that identifies the tile that will be encoded -*/ -void tcd_malloc_encode(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp, int curtileno); -/** -Free the memory allocated for encoding -@param tcd TCD handle + * 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). */ -void tcd_free_encode(opj_tcd_t *tcd); +bool tcd_init( + opj_tcd_t *p_tcd, + struct opj_image * p_image, + struct opj_cp * p_cp + ); + + /** -Initialize the tile coder (reuses the memory allocated by tcd_malloc_encode) -@param tcd TCD handle -@param image Raw image -@param cp Coding parameters -@param curtileno Number that identifies the tile that will be encoded -*/ -void tcd_init_encode(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp, int curtileno); + * 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 + */ +bool tcd_init_decode_tile( + opj_tcd_t *p_tcd, + OPJ_UINT32 p_tile_no + ); /** -Initialize the tile decoder -@param tcd TCD handle -@param image Raw image -@param cp Coding parameters + * 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). */ -void tcd_malloc_decode(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp); -void tcd_malloc_decode_tile(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp, int tileno, opj_codestream_info_t *cstr_info); -void tcd_makelayer_fixed(opj_tcd_t *tcd, int layno, int final); +bool tcd_init_encode_tile + ( + opj_tcd_t *p_tcd, + OPJ_UINT32 p_tile_no + ); + +void tcd_makelayer_fixed(opj_tcd_t *tcd, OPJ_UINT32 layno, OPJ_UINT32 final); void tcd_rateallocate_fixed(opj_tcd_t *tcd); -void tcd_makelayer(opj_tcd_t *tcd, int layno, double thresh, int final); -bool tcd_rateallocate(opj_tcd_t *tcd, unsigned char *dest, int len, opj_codestream_info_t *cstr_info); +void tcd_makelayer(opj_tcd_t *tcd, OPJ_UINT32 layno, OPJ_FLOAT64 thresh, OPJ_UINT32 final); +bool tcd_rateallocate(opj_tcd_t *tcd, OPJ_BYTE *dest, OPJ_UINT32 * p_data_written, OPJ_UINT32 len, struct opj_codestream_info *cstr_info); /** -Encode a tile from the raw image into a buffer -@param tcd TCD handle -@param tileno Number that identifies one of the tiles to be encoded -@param dest Destination buffer -@param len Length of destination buffer -@param cstr_info Codestream information structure -@return + * Encodes a tile from the raw image into the given buffer. + * @param p_tcd Tile Coder handle + * @param p_tile_no Index of the tile to encode. + * @param p_dest Destination buffer + * @param p_data_written pointer to an int that is incremented by the number of bytes really written on p_dest + * @param p_len Maximum length of the destination buffer + * @param p_cstr_info Codestream information structure + * @return true if the coding is successfull. */ -int tcd_encode_tile(opj_tcd_t *tcd, int tileno, unsigned char *dest, int len, opj_codestream_info_t *cstr_info); +bool tcd_encode_tile(opj_tcd_t *p_tcd, OPJ_UINT32 p_tile_no, OPJ_BYTE *p_dest, OPJ_UINT32 * p_data_written, OPJ_UINT32 p_len, struct opj_codestream_info *p_cstr_info); + /** Decode a tile from a buffer into a raw image @param tcd TCD handle @@ -269,14 +308,34 @@ Decode a tile from a buffer into a raw image @param len Length of source buffer @param tileno Number that identifies one of the tiles to be decoded */ -bool tcd_decode_tile(opj_tcd_t *tcd, unsigned char *src, int len, int tileno, opj_codestream_info_t *cstr_info); +bool tcd_decode_tile(opj_tcd_t *tcd, OPJ_BYTE *src, OPJ_UINT32 len, OPJ_UINT32 tileno, struct opj_codestream_info *cstr_info); + /** -Free the memory allocated for decoding -@param tcd TCD handle -*/ -void tcd_free_decode(opj_tcd_t *tcd); -void tcd_free_decode_tile(opj_tcd_t *tcd, int tileno); + * Copies tile data from the given memory block onto the system. + */ +bool tcd_copy_tile_data ( + opj_tcd_t *p_tcd, + OPJ_BYTE * p_src, + OPJ_UINT32 p_src_length + ); +/** + * Copies tile data from the system onto the given memory block. + */ +bool tcd_update_tile_data ( + opj_tcd_t *p_tcd, + OPJ_BYTE * p_dest, + OPJ_UINT32 p_dest_length + ); +/** + * Gets the maximum tile size that will be taken by the tile once decoded. + */ +OPJ_UINT32 tcd_get_decoded_tile_size ( + opj_tcd_t *p_tcd + ); +OPJ_UINT32 tcd_get_encoded_tile_size ( + opj_tcd_t *p_tcd + ); /* ----------------------------------------------------------------------- */ /*@}*/ diff --git a/libopenjpeg/tgt.c b/libopenjpeg/tgt.c index a5dbcd3c..70147b38 100644 --- a/libopenjpeg/tgt.c +++ b/libopenjpeg/tgt.c @@ -5,6 +5,7 @@ * Copyright (c) 2002-2003, Yannick Verschueren * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,7 +30,9 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "opj_includes.h" +#include "tgt.h" +#include "bio.h" +#include "opj_malloc.h" /* ========================================================== @@ -37,19 +40,22 @@ ========================================================== */ -opj_tgt_tree_t *tgt_create(int numleafsh, int numleafsv) { - int nplh[32]; - int nplv[32]; - opj_tgt_node_t *node = NULL; - opj_tgt_node_t *parentnode = NULL; - opj_tgt_node_t *parentnode0 = NULL; - opj_tgt_tree_t *tree = NULL; - int i, j, k; - int numlvls; - int n; +opj_tgt_tree_t *tgt_create(OPJ_UINT32 numleafsh, OPJ_UINT32 numleafsv) { + OPJ_INT32 nplh[32]; + OPJ_INT32 nplv[32]; + opj_tgt_node_t *node = 00; + opj_tgt_node_t *l_parent_node = 00; + opj_tgt_node_t *l_parent_node0 = 00; + opj_tgt_tree_t *tree = 00; + OPJ_UINT32 i; + OPJ_INT32 j,k; + OPJ_UINT32 numlvls; + OPJ_UINT32 n; tree = (opj_tgt_tree_t *) opj_malloc(sizeof(opj_tgt_tree_t)); - if(!tree) return NULL; + if(!tree) return 00; + memset(tree,0,sizeof(opj_tgt_tree_t)); + tree->numleafsh = numleafsh; tree->numleafsv = numleafsv; @@ -68,65 +74,190 @@ opj_tgt_tree_t *tgt_create(int numleafsh, int numleafsv) { /* ADD */ if (tree->numnodes == 0) { opj_free(tree); - return NULL; + return 00; } tree->nodes = (opj_tgt_node_t*) opj_calloc(tree->numnodes, sizeof(opj_tgt_node_t)); if(!tree->nodes) { opj_free(tree); - return NULL; + return 00; } + memset(tree->nodes,0,tree->numnodes * sizeof(opj_tgt_node_t)); + tree->nodes_size = tree->numnodes * sizeof(opj_tgt_node_t); node = tree->nodes; - parentnode = &tree->nodes[tree->numleafsh * tree->numleafsv]; - parentnode0 = parentnode; + l_parent_node = &tree->nodes[tree->numleafsh * tree->numleafsv]; + l_parent_node0 = l_parent_node; for (i = 0; i < numlvls - 1; ++i) { for (j = 0; j < nplv[i]; ++j) { k = nplh[i]; while (--k >= 0) { - node->parent = parentnode; + node->parent = l_parent_node; ++node; if (--k >= 0) { - node->parent = parentnode; + node->parent = l_parent_node; ++node; } - ++parentnode; + ++l_parent_node; } if ((j & 1) || j == nplv[i] - 1) { - parentnode0 = parentnode; + l_parent_node0 = l_parent_node; } else { - parentnode = parentnode0; - parentnode0 += nplh[i]; + l_parent_node = l_parent_node0; + l_parent_node0 += nplh[i]; } } } node->parent = 0; - tgt_reset(tree); - 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); +void tgt_destroy(opj_tgt_tree_t *p_tree) +{ + if + (! p_tree) + { + return; + } + if + (p_tree->nodes) + { + opj_free(p_tree->nodes); + p_tree->nodes = 00; + } + opj_free(p_tree); } -void tgt_reset(opj_tgt_tree_t *tree) { - int i; +void tgt_reset(opj_tgt_tree_t *p_tree) { + OPJ_UINT32 i; + opj_tgt_node_t * l_current_node = 00;; - if (NULL == tree) + if + (! p_tree) + { return; - - for (i = 0; i < tree->numnodes; i++) { - tree->nodes[i].value = 999; - tree->nodes[i].low = 0; - tree->nodes[i].known = 0; + } + l_current_node = p_tree->nodes; + for + (i = 0; i < p_tree->numnodes; ++i) + { + l_current_node->value = 999; + l_current_node->low = 0; + l_current_node->known = 0; + ++l_current_node; } } -void tgt_setvalue(opj_tgt_tree_t *tree, int leafno, int value) { +void tgt_setvalue(opj_tgt_tree_t *tree, OPJ_UINT32 leafno, OPJ_INT32 value) { opj_tgt_node_t *node; node = &tree->nodes[leafno]; while (node && node->value > value) { @@ -135,11 +266,11 @@ void tgt_setvalue(opj_tgt_tree_t *tree, int leafno, int value) { } } -void tgt_encode(opj_bio_t *bio, opj_tgt_tree_t *tree, int leafno, int threshold) { +void tgt_encode(opj_bio_t *bio, opj_tgt_tree_t *tree, OPJ_UINT32 leafno, OPJ_INT32 threshold) { opj_tgt_node_t *stk[31]; opj_tgt_node_t **stkptr; opj_tgt_node_t *node; - int low; + OPJ_INT32 low; stkptr = stk; node = &tree->nodes[leafno]; @@ -175,11 +306,11 @@ void tgt_encode(opj_bio_t *bio, opj_tgt_tree_t *tree, int leafno, int threshold) } } -int tgt_decode(opj_bio_t *bio, opj_tgt_tree_t *tree, int leafno, int threshold) { +OPJ_UINT32 tgt_decode(opj_bio_t *bio, opj_tgt_tree_t *tree, OPJ_UINT32 leafno, OPJ_INT32 threshold) { opj_tgt_node_t *stk[31]; opj_tgt_node_t **stkptr; opj_tgt_node_t *node; - int low; + OPJ_INT32 low; stkptr = stk; node = &tree->nodes[leafno]; diff --git a/libopenjpeg/tgt.h b/libopenjpeg/tgt.h index c08c8da0..fe1b85f5 100644 --- a/libopenjpeg/tgt.h +++ b/libopenjpeg/tgt.h @@ -5,6 +5,7 @@ * Copyright (c) 2002-2003, Yannick Verschueren * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -38,28 +39,32 @@ The functions in TGT.C have for goal to realize a tag-tree coder. The functions in TGT.C are used by some function in T2.C. */ - +#include "openjpeg.h" /** @defgroup TGT TGT - Implementation of a tag-tree coder */ /*@{*/ +struct opj_bio; /** Tag node */ -typedef struct opj_tgt_node { +typedef struct opj_tgt_node +{ struct opj_tgt_node *parent; - int value; - int low; - int known; + OPJ_INT32 value; + OPJ_INT32 low; + OPJ_UINT32 known : 1; } opj_tgt_node_t; /** Tag tree */ -typedef struct opj_tgt_tree { - int numleafsh; - int numleafsv; - int numnodes; +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 */ @@ -71,7 +76,18 @@ Create a tag-tree @param numleafsv Height of the array of leafs of the tree @return Returns a new tag-tree if successful, returns NULL otherwise */ -opj_tgt_tree_t *tgt_create(int numleafsh, int numleafsv); +opj_tgt_tree_t *tgt_create(OPJ_UINT32 numleafsh, OPJ_UINT32 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 @@ -88,7 +104,7 @@ Set the value of a leaf of a tag-tree @param leafno Number that identifies the leaf to modify @param value New value of the leaf */ -void tgt_setvalue(opj_tgt_tree_t *tree, int leafno, int value); +void tgt_setvalue(opj_tgt_tree_t *tree, OPJ_UINT32 leafno, OPJ_INT32 value); /** Encode the value of a leaf of the tag-tree up to a given threshold @param bio Pointer to a BIO handle @@ -96,7 +112,7 @@ Encode the value of a leaf of the tag-tree up to a given threshold @param leafno Number that identifies the leaf to encode @param threshold Threshold to use when encoding value of the leaf */ -void tgt_encode(opj_bio_t *bio, opj_tgt_tree_t *tree, int leafno, int threshold); +void tgt_encode(struct opj_bio *bio, opj_tgt_tree_t *tree, OPJ_UINT32 leafno, OPJ_INT32 threshold); /** Decode the value of a leaf of the tag-tree up to a given threshold @param bio Pointer to a BIO handle @@ -105,7 +121,7 @@ Decode the value of a leaf of the tag-tree up to a given threshold @param threshold Threshold to use when decoding value of the leaf @return Returns 1 if the node's value < threshold, returns 0 otherwise */ -int tgt_decode(opj_bio_t *bio, opj_tgt_tree_t *tree, int leafno, int threshold); +OPJ_UINT32 tgt_decode(struct opj_bio *bio, opj_tgt_tree_t *tree, OPJ_UINT32 leafno, OPJ_INT32 threshold); /* ----------------------------------------------------------------------- */ /*@}*/ |
