From: Mickael Savinaud Date: Thu, 15 Mar 2012 10:23:20 +0000 (+0000) Subject: [trunk] modify image_to_j2k and the lib to support functionalities given by the v2... X-Git-Tag: version.2.0~475 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3a78e8010d0f1e206355d660a21f23898cf5fbc0;p=openjpeg [trunk] modify image_to_j2k and the lib to support functionalities given by the v2 alpha branch --- diff --git a/applications/codec/image_to_j2k.c b/applications/codec/image_to_j2k.c index cbdc1e60..7d2bba0d 100644 --- a/applications/codec/image_to_j2k.c +++ b/applications/codec/image_to_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 * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -211,6 +212,8 @@ void encode_help_display(void) { fprintf(stdout," -F rawWidth,rawHeight,rawComp,rawBitDepth,s/u (Signed/Unsigned)\n"); fprintf(stdout," Example: -i lena.raw -o lena.j2k -F 512,512,3,8,u\n"); fprintf(stdout,"\n"); + fprintf(stdout,"-m : use array-based MCT, values are coma separated, line by line\n"); + fprintf(stdout," no specific separators between lines, no space allowed between values\n"); fprintf(stdout,"-jpip : write jpip codestream index box in JP2 output file\n"); fprintf(stdout," NOTICE: currently supports only RPCL order\n"); fprintf(stdout,"\n"); @@ -1054,6 +1057,73 @@ int parse_cmdline_encoder(int argc, char **argv, opj_cparameters_t *parameters, } break; + /* ------------------------------------------------------ */ + case 'm': /* mct input file */ + { + char *lFilename = opj_optarg; + char *lMatrix; + char *lCurrentPtr ; + float *lCurrentDoublePtr; + float *lSpace; + int *l_int_ptr; + int lNbComp = 0, lTotalComp, lMctComp, i, lStrLen; + + /* Open file */ + FILE * lFile = fopen(lFilename,"r"); + if (lFile == NULL) { + return 1; + } + + /* Set size of file and read its content*/ + fseek(lFile,0,SEEK_END); + lStrLen = ftell(lFile); + fseek(lFile,0,SEEK_SET); + lMatrix = (char *) malloc(lStrLen + 1); + fread(lMatrix, lStrLen, 1, lFile); + fclose(lFile); + + lMatrix[lStrLen] = 0; + lCurrentPtr = lMatrix; + + /* replace ',' by 0 */ + while (*lCurrentPtr != 0 ) { + if (*lCurrentPtr == ' ') { + *lCurrentPtr = 0; + ++lNbComp; + } + ++lCurrentPtr; + } + ++lNbComp; + lCurrentPtr = lMatrix; + + lNbComp = (int) (sqrt(4*lNbComp + 1)/2. - 0.5); + lMctComp = lNbComp * lNbComp; + lTotalComp = lMctComp + lNbComp; + lSpace = (float *) malloc(lTotalComp * sizeof(float)); + lCurrentDoublePtr = lSpace; + for (i=0;i> */ @@ -1486,20 +1556,30 @@ void info_callback(const char *msg, void *client_data) { } /* -------------------------------------------------------------------------- */ - +/** + * IMAGE_TO_J2K MAIN + */ +/* -------------------------------------------------------------------------- */ int main(int argc, char **argv) { - opj_bool bSuccess; + FILE *f = NULL; + opj_cparameters_t parameters; /* compression parameters */ - img_fol_t img_fol; opj_event_mgr_t event_mgr; /* event manager */ + + opj_stream_t *cio = 00; + opj_codec_t* cinfo = 00; opj_image_t *image = NULL; - int i,num_images; - int imageno; - dircnt_t *dirptr = NULL; raw_cparameters_t raw_cp; opj_codestream_info_t cstr_info; /* Codestream information structure */ + char indexfilename[OPJ_PATH_LEN]; /* index file name */ + int i, num_images, imageno; + img_fol_t img_fol; + dircnt_t *dirptr = NULL; + + opj_bool bSuccess; + /* configure the event callbacks (not required) setting of each callback is optionnal @@ -1580,6 +1660,7 @@ int main(int argc, char **argv) { continue; } } + switch(parameters.decod_format) { case PGX_DFMT: break; @@ -1600,213 +1681,151 @@ int main(int argc, char **argv) { continue; } - /* decode the source image */ - /* ----------------------- */ + /* decode the source image */ + /* ----------------------- */ - switch (parameters.decod_format) { - case PGX_DFMT: - image = pgxtoimage(parameters.infile, ¶meters); - if (!image) { - fprintf(stderr, "Unable to load pgx file\n"); - return 1; - } - break; + switch (parameters.decod_format) { + case PGX_DFMT: + image = pgxtoimage(parameters.infile, ¶meters); + if (!image) { + fprintf(stderr, "Unable to load pgx file\n"); + return 1; + } + break; - case PXM_DFMT: - image = pnmtoimage(parameters.infile, ¶meters); - if (!image) { - fprintf(stderr, "Unable to load pnm file\n"); - return 1; - } - break; + case PXM_DFMT: + image = pnmtoimage(parameters.infile, ¶meters); + if (!image) { + fprintf(stderr, "Unable to load pnm file\n"); + return 1; + } + break; - case BMP_DFMT: - image = bmptoimage(parameters.infile, ¶meters); - if (!image) { - fprintf(stderr, "Unable to load bmp file\n"); - return 1; - } - break; -#ifdef HAVE_LIBTIFF - case TIF_DFMT: - image = tiftoimage(parameters.infile, ¶meters); - if (!image) { - fprintf(stderr, "Unable to load tiff file\n"); - return 1; - } + case BMP_DFMT: + image = bmptoimage(parameters.infile, ¶meters); + if (!image) { + fprintf(stderr, "Unable to load bmp file\n"); + return 1; + } break; + +#ifdef HAVE_LIBTIFF + case TIF_DFMT: + image = tiftoimage(parameters.infile, ¶meters); + if (!image) { + fprintf(stderr, "Unable to load tiff file\n"); + return 1; + } + break; #endif /* HAVE_LIBTIFF */ - case RAW_DFMT: - image = rawtoimage(parameters.infile, ¶meters, &raw_cp); - if (!image) { - fprintf(stderr, "Unable to load raw file\n"); - return 1; - } - break; - case TGA_DFMT: - image = tgatoimage(parameters.infile, ¶meters); - if (!image) { - fprintf(stderr, "Unable to load tga file\n"); - return 1; - } - break; + case RAW_DFMT: + image = rawtoimage(parameters.infile, ¶meters, &raw_cp); + if (!image) { + fprintf(stderr, "Unable to load raw file\n"); + return 1; + } + break; + + case TGA_DFMT: + image = tgatoimage(parameters.infile, ¶meters); + if (!image) { + fprintf(stderr, "Unable to load tga file\n"); + return 1; + } + break; + #ifdef HAVE_LIBPNG - case PNG_DFMT: - image = pngtoimage(parameters.infile, ¶meters); - if (!image) { - fprintf(stderr, "Unable to load png file\n"); - return 1; - } - break; + case PNG_DFMT: + image = pngtoimage(parameters.infile, ¶meters); + if (!image) { + fprintf(stderr, "Unable to load png file\n"); + return 1; + } + break; #endif /* HAVE_LIBPNG */ } + /* Can happen if input file is TIFF or PNG * and HAVE_LIBTIF or HAVE_LIBPNG is undefined */ - if( !image) - { + if( !image) { fprintf(stderr, "Unable to load file: got no image\n"); return 1; - } - /* Decide if MCT should be used */ - parameters.tcp_mct = image->numcomps == 3 ? 1 : 0; + } - if(parameters.cp_cinema){ - cinema_setup_encoder(¶meters,image,&img_fol); - } + /* Decide if MCT should be used */ + parameters.tcp_mct = image->numcomps == 3 ? 1 : 0; - /* encode the destination image */ - /* ---------------------------- */ + if(parameters.cp_cinema){ + cinema_setup_encoder(¶meters,image,&img_fol); + } - if (parameters.cod_format == J2K_CFMT) { /* J2K format output */ - int codestream_length; - size_t res; - opj_cio_t *cio = NULL; - FILE *f = NULL; + /* encode the destination image */ + /* ---------------------------- */ - /* get a J2K compressor handle */ - opj_cinfo_t* cinfo = opj_create_compress(CODEC_J2K); + switch(parameters.decod_format) { + case J2K_CFMT: /* JPEG-2000 codestream */ + { + /* Get a decoder handle */ + cinfo = opj_create_compress_v2(CODEC_J2K); + break; + } + case JP2_CFMT: /* JPEG 2000 compressed image data */ + { + /* Get a decoder handle */ + cinfo = opj_create_compress_v2(CODEC_JP2); + break; + } + default: + fprintf(stderr, "skipping file..\n"); + opj_stream_destroy(cio); + continue; + } - /* catch events using our callbacks and give a local context */ - opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr); + opj_setup_encoder_v2(cinfo, ¶meters, image); - /* setup the encoder parameters using the current image and user parameters */ - opj_setup_encoder(cinfo, ¶meters, image); + /* Open the output file*/ + f = fopen(parameters.outfile, "wb"); + if (! f) { + fprintf(stderr, "Not enable to create output file!\n"); + opj_stream_destroy(cio); + return 1; + } - /* open a byte stream for writing */ - /* allocate memory for all tiles */ - cio = opj_cio_open((opj_common_ptr)cinfo, NULL, 0); + /* open a byte stream for writing and allocate memory for all tiles */ + cio = opj_stream_create_default_file_stream(f,OPJ_FALSE); + if (! cio){ + return 1; + } - /* encode the image */ - if (*indexfilename) /* If need to extract codestream information*/ - bSuccess = opj_encode_with_info(cinfo, cio, image, &cstr_info); - else - bSuccess = opj_encode(cinfo, cio, image, NULL); - if (!bSuccess) { - opj_cio_close(cio); - fprintf(stderr, "failed to encode image\n"); - return 1; - } - codestream_length = cio_tell(cio); + /* encode the image */ + bSuccess = opj_start_compress(cinfo,image,cio); + bSuccess = bSuccess && opj_encode_v2(cinfo, cio); + bSuccess = bSuccess && opj_end_compress(cinfo, cio); - /* write the buffer to disk */ - f = fopen(parameters.outfile, "wb"); - if (!f) { - fprintf(stderr, "failed to open %s for writing\n", parameters.outfile); - return 1; - } - res = fwrite(cio->buffer, 1, codestream_length, f); - if( res < (size_t)codestream_length ) { /* FIXME */ - fprintf(stderr, "failed to write %d (%s)\n", codestream_length, parameters.outfile); - return 1; - } - fclose(f); - - fprintf(stderr,"Generated outfile %s\n",parameters.outfile); - /* close and free the byte stream */ - opj_cio_close(cio); - - /* Write the index to disk */ - if (*indexfilename) { - bSuccess = write_index_file(&cstr_info, indexfilename); - if (bSuccess) { - fprintf(stderr, "Failed to output index file into [%s]\n", indexfilename); - } - } + if (!bSuccess) { + opj_stream_destroy(cio); + fclose(f); + fprintf(stderr, "failed to encode image\n"); + return 1; + } - /* free remaining compression structures */ - opj_destroy_compress(cinfo); - if (*indexfilename) - opj_destroy_cstr_info(&cstr_info); - } else { /* JP2 format output */ - int codestream_length; - size_t res; - opj_cio_t *cio = NULL; - FILE *f = NULL; - opj_cinfo_t *cinfo = NULL; - - /* get a JP2 compressor handle */ - cinfo = opj_create_compress(CODEC_JP2); - - /* catch events using our callbacks and give a local context */ - opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr); - - /* setup the encoder parameters using the current image and using user parameters */ - opj_setup_encoder(cinfo, ¶meters, image); - - /* open a byte stream for writing */ - /* allocate memory for all tiles */ - cio = opj_cio_open((opj_common_ptr)cinfo, NULL, 0); - - /* encode the image */ - if (*indexfilename || parameters.jpip_on) /* If need to extract codestream information*/ - bSuccess = opj_encode_with_info(cinfo, cio, image, &cstr_info); - else - bSuccess = opj_encode(cinfo, cio, image, NULL); - if (!bSuccess) { - opj_cio_close(cio); - fprintf(stderr, "failed to encode image\n"); - return 1; - } - codestream_length = cio_tell(cio); + fprintf(stderr,"Generated outfile %s\n",parameters.outfile); + /* close and free the byte stream */ + opj_stream_destroy(cio); + fclose(f); - /* write the buffer to disk */ - f = fopen(parameters.outfile, "wb"); - if (!f) { - fprintf(stderr, "failed to open %s for writing\n", parameters.outfile); - return 1; - } - res = fwrite(cio->buffer, 1, codestream_length, f); - if( res < (size_t)codestream_length ) { /* FIXME */ - fprintf(stderr, "failed to write %d (%s)\n", codestream_length, parameters.outfile); - return 1; - } - fclose(f); - fprintf(stderr,"Generated outfile %s\n",parameters.outfile); - /* close and free the byte stream */ - opj_cio_close(cio); - - /* Write the index to disk */ - if (*indexfilename) { - bSuccess = write_index_file(&cstr_info, indexfilename); - if (bSuccess) { - fprintf(stderr, "Failed to output index file\n"); - } - } + /* free remaining compression structures */ + opj_destroy_codec(cinfo); - /* free remaining compression structures */ - opj_destroy_compress(cinfo); - if (*indexfilename) - opj_destroy_cstr_info(&cstr_info); - } + /* free image data */ + opj_image_destroy(image); - /* free image data */ - opj_image_destroy(image); } /* free user parameters structure */ - if(parameters.cp_comment) free(parameters.cp_comment); + if(parameters.cp_comment) free(parameters.cp_comment); if(parameters.cp_matrice) free(parameters.cp_matrice); return 0; diff --git a/libopenjpeg/dwt.c b/libopenjpeg/dwt.c index 1b4ad48b..13a3001b 100644 --- a/libopenjpeg/dwt.c +++ b/libopenjpeg/dwt.c @@ -128,6 +128,12 @@ Inverse wavelet transform in 2-D. */ static opj_bool dwt_decode_tile_v2(opj_tcd_tilecomp_v2_t* tilec, OPJ_UINT32 i, DWT1DFN fn); +static opj_bool dwt_encode_procedure( opj_tcd_tilecomp_v2_t * tilec, + void (*p_function)(OPJ_INT32 *, OPJ_INT32,OPJ_INT32,OPJ_INT32) ); + +static OPJ_UINT32 dwt_max_resolution_v2(opj_tcd_resolution_v2_t* restrict r, OPJ_UINT32 i); + + /*@}*/ /*@}*/ @@ -383,6 +389,95 @@ void dwt_encode(opj_tcd_tilecomp_t * tilec) { } } +/* */ +/* Forward 5-3 wavelet transform in 2-D. */ +/* */ +INLINE opj_bool dwt_encode_procedure(opj_tcd_tilecomp_v2_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_v2_t * l_cur_res = 0; + opj_tcd_resolution_v2_t * l_last_res = 0; + + w = tilec->x1-tilec->x0; + l = tilec->numresolutions-1; + a = tilec->data; + + 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_v2( tilec->resolutions,tilec->numresolutions) * sizeof(OPJ_INT32); + bj = (OPJ_INT32*)opj_malloc(l_data_size); + if (! bj) { + return OPJ_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 = 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 = l_cur_res->x0 & 1; + cas_col = l_cur_res->y0 & 1; + + sn = rh1; + dn = rh - rh1; + for (j = 0; j < rw; ++j) { + aj = a + j; + 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); + } + + sn = rw1; + dn = rw - rw1; + + for (j = 0; j < rh; j++) { + aj = a + j * w; + for (k = 0; k < rw; k++) bj[k] = aj[k]; + (*p_function) (bj, dn, sn, cas_row); + dwt_deinterleave_h(bj, aj, dn, sn, cas_row); + } + + l_cur_res = l_last_res; + + --l_last_res; + } + + opj_free(bj); + return OPJ_TRUE; +} + +/* Forward 5-3 wavelet transform in 2-D. */ +/* */ +opj_bool dwt_encode_v2(opj_tcd_tilecomp_v2_t * tilec) +{ + return dwt_encode_procedure(tilec,dwt_encode_1); +} + #ifdef OPJ_V1 /* */ /* Inverse 5-3 wavelet transform in 2-D. */ @@ -492,6 +587,13 @@ void dwt_encode_real(opj_tcd_tilecomp_t * tilec) { } } +/* */ +/* Forward 9-7 wavelet transform in 2-D. */ +/* */ +opj_bool dwt_encode_real_v2(opj_tcd_tilecomp_v2_t * tilec) +{ + return dwt_encode_procedure(tilec,dwt_encode_1_real); +} /* */ /* Get gain of 9-7 wavelet transform. */ diff --git a/libopenjpeg/dwt.h b/libopenjpeg/dwt.h index a43882dc..3b833391 100644 --- a/libopenjpeg/dwt.h +++ b/libopenjpeg/dwt.h @@ -52,6 +52,13 @@ 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) */ +opj_bool dwt_encode_v2(struct opj_tcd_tilecomp_v2 * tilec); + +/** +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); /** Inverse 5-3 wavelet tranform in 2-D. @@ -87,6 +94,7 @@ 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); +opj_bool dwt_encode_real_v2(opj_tcd_tilecomp_v2_t * tilec); /** KEEP TRUNK VERSION + return type of v2 because rev557 Inverse 9-7 wavelet transform in 2-D. diff --git a/libopenjpeg/int.h b/libopenjpeg/int.h index a39772b0..57fec99d 100644 --- a/libopenjpeg/int.h +++ b/libopenjpeg/int.h @@ -104,6 +104,15 @@ Divide an integer and round upwards static INLINE int int_ceildiv(int a, int 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 diff --git a/libopenjpeg/j2k.c b/libopenjpeg/j2k.c index 2194e6d5..0d7f62bc 100644 --- a/libopenjpeg/j2k.c +++ b/libopenjpeg/j2k.c @@ -54,6 +54,19 @@ opj_bool j2k_read_header_procedure( 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. + */ +opj_bool j2k_encoding_validation ( opj_j2k_v2_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ); + /** * The default decoding validation procedure without any extension. * @@ -69,20 +82,60 @@ opj_bool j2k_decoding_validation ( opj_event_mgr_t * p_manager ); +/** + * Sets up the validation ,i.e. adds the procedures to lauch to make sure the codec parameters + * are valid. Developpers wanting to extend the library can add their own validation procedures. + */ +static void j2k_setup_encoding_validation (opj_j2k_v2_t *p_j2k); + /** * Sets up the validation ,i.e. adds the procedures to lauch to make sure the codec parameters * are valid. Developpers wanting to extend the library can add their own validation procedures. */ static void j2k_setup_decoding_validation (opj_j2k_v2_t *p_j2k); +/** + * Sets up the validation ,i.e. adds the procedures to lauch to make sure the codec parameters + * are valid. Developpers wanting to extend the library can add their own validation procedures. + */ +static void j2k_setup_end_compress (opj_j2k_v2_t *p_j2k); + +/** + * The mct encoding validation procedure. + * + * @param p_j2k the jpeg2000 codec to validate. + * @param p_stream the input stream to validate. + * @param p_manager the user event manager. + * + * @return true if the parameters are correct. + */ +opj_bool j2k_mct_validation ( opj_j2k_v2_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ); + /** * Builds the tcd decoder to use to decode tile. */ -opj_bool j2k_build_decoder ( - opj_j2k_v2_t * p_j2k, - opj_stream_private_t *p_stream, - opj_event_mgr_t * p_manager - ); +opj_bool j2k_build_decoder (opj_j2k_v2_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ); +/** + * Builds the tcd encoder to use to encode tile. + */ +opj_bool j2k_build_encoder (opj_j2k_v2_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ); + +/** + * Creates a tile-coder decoder. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_create_tcd( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); /** * Excutes the given procedures on the given codec. @@ -101,6 +154,17 @@ static opj_bool j2k_exec ( opj_event_mgr_t * p_manager ); +/** + * Updates the rates of the tcp. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_update_rates( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + /** * Copies the decoding tile parameters onto all the tile parameters. * Creates also the tile decoder. @@ -109,6 +173,13 @@ opj_bool j2k_copy_default_tcp_and_create_tcd ( opj_j2k_v2_t * p_j2k, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager ); +/** + * Destroys the memory associated with the decoding of headers. + */ +opj_bool j2k_destroy_header_memory (opj_j2k_v2_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ); + /** * Reads the lookup table containing all the marker, status and action, and returns the handler associated * with the marker value. @@ -140,6 +211,35 @@ static void j2k_tcp_data_destroy (opj_tcp_v2_t *p_tcp); static void j2k_cp_destroy (opj_cp_v2_t *p_cp); +/** + * Writes a SPCod or SPCoc element, i.e. the coding style of a given component of a tile. + * + * @param p_comp_no the component number to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. + * +*/ +static opj_bool j2k_write_SPCod_SPCoc( opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_header_size, + struct opj_event_mgr * p_manager ); + +/** + * Gets the size taken by writing a SPCod or SPCoc for the given tile and component. + * + * @param p_tile_no the tile index. + * @param p_comp_no the component being outputted. + * @param p_j2k the J2K codec. + * + * @return the number of bytes taken by the SPCod element. + */ +static OPJ_UINT32 j2k_get_SPCod_SPCoc_size (opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no ); + /** * Reads a SPCod or SPCoc element, i.e. the coding style of a given component of a tile. * @param p_header_data the data contained in the COM box. @@ -155,6 +255,43 @@ static opj_bool j2k_read_SPCod_SPCoc( struct opj_event_mgr * p_manager ); +/** + * Gets the size taken by writing SQcd or SQcc element, i.e. the quantization values of a band in the QCD or QCC. + * + * @param p_tile_no the tile index. + * @param p_comp_no the component being outputted. + * @param p_j2k the J2K codec. + * + * @return the number of bytes taken by the SPCod element. + */ +static OPJ_UINT32 j2k_get_SQcd_SQcc_size ( opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no ); + +/** + * Writes a SQcd or SQcc element, i.e. the quantization values of a band in the QCD or QCC. + * + * @param p_tile_no the tile to output. + * @param p_comp_no the component number to output. + * @param p_data the data buffer. + * @param p_header_size pointer to the size of the data buffer, it is changed by the function. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. + * +*/ +static opj_bool j2k_write_SQcd_SQcc(opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_header_size, + struct opj_event_mgr * p_manager + ); + +/** + * Updates the Tile Length Marker. + */ +static void j2k_update_tlm ( opj_j2k_v2_t * p_j2k, OPJ_UINT32 p_tile_part_size); + /** * Reads a SQcd or SQcc element, i.e. the quantization values of a band in the QCD or QCC. * @@ -195,12 +332,56 @@ static void j2k_copy_tile_quantization_parameters( /** * Reads the tiles. */ -opj_bool j2k_decode_tiles ( opj_j2k_v2_t *p_j2k, - opj_stream_private_t *p_stream, - opj_event_mgr_t * p_manager); +opj_bool j2k_decode_tiles ( opj_j2k_v2_t *p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager); + + +static opj_bool j2k_pre_write_tile ( opj_j2k_v2_t * p_j2k, + OPJ_UINT32 p_tile_index, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ); static opj_bool j2k_update_image_data (opj_tcd_v2_t * p_tcd, OPJ_BYTE * p_data, opj_image_t* p_output_image); +static void j2k_get_tile_data (opj_tcd_v2_t * p_tcd, OPJ_BYTE * p_data); + +static opj_bool j2k_post_write_tile (opj_j2k_v2_t * p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 p_data_size, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ); + +/** + * Sets up the procedures to do on writing header. + * Developers wanting to extend the library can add their own writing procedures. + */ +void j2k_setup_header_writting (opj_j2k_v2_t *p_j2k); + +static opj_bool j2k_write_first_tile_part( opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 p_total_data_size, + opj_stream_private_t *p_stream, + struct opj_event_mgr * p_manager ); + +static opj_bool j2k_write_all_tile_parts( opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 p_total_data_size, + opj_stream_private_t *p_stream, + struct opj_event_mgr * p_manager ); + +/** + * Gets the offset of the header. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_get_end_header( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); /* * ----------------------------------------------------------------------- @@ -213,6 +394,18 @@ Write the SOC marker (Start Of Codestream) @param j2k J2K handle */ static void j2k_write_soc(opj_j2k_t *j2k); + +/** + * Writes the SOC marker (Start Of Codestream) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_soc_v2( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + /** Read the SOC marker (Start of Codestream) @param j2k J2K handle @@ -237,6 +430,18 @@ Write the SIZ marker (image and tile size) @param j2k J2K handle */ static void j2k_write_siz(opj_j2k_t *j2k); + +/** + * Writes the SIZ marker (image and tile size) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_siz_v2( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + /** Read the SIZ marker (image and tile size) @param j2k J2K handle @@ -297,6 +502,18 @@ Write the COD marker (coding style default) @param j2k J2K handle */ static void j2k_write_cod(opj_j2k_t *j2k); + +/** + * Writes the COD marker (Coding style default) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_cod_v2( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + /** Read the COD marker (coding style default) @param j2k J2K handle @@ -323,6 +540,41 @@ Write the COC marker (coding style component) @param compno Number of the component concerned by the information written */ static void j2k_write_coc(opj_j2k_t *j2k, int compno); + +/** + * Writes the COC marker (Coding style component) + * + * @param p_comp_number the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_coc_v2( opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_comp_number, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); +/** + * Writes the COC marker (Coding style component) + * + * @param p_comp_no the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static void j2k_write_coc_in_memory(opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_comp_no, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + struct opj_event_mgr * p_manager ); + +/** + * Gets the maximum size taken by a coc. + * + * @param p_j2k the jpeg2000 codec to use. + */ +static OPJ_UINT32 j2k_get_max_coc_size(opj_j2k_v2_t *p_j2k); + /** Read the COC marker (coding style component) @param j2k J2K handle @@ -361,6 +613,19 @@ Write the QCD marker (quantization default) @param j2k J2K handle */ static void j2k_write_qcd(opj_j2k_t *j2k); + +/** + * Writes the QCD marker (quantization default) + * + * @param p_comp_number the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_qcd_v2( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + /** Read the QCD marker (quantization default) @param j2k J2K handle @@ -387,6 +652,39 @@ Write the QCC marker (quantization component) @param compno Number of the component concerned by the information written */ static void j2k_write_qcc(opj_j2k_t *j2k, int compno); + +/** + * Writes the QCC marker (quantization component) + * + * @param p_comp_no the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_qcc_v2( opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_comp_no, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + +/** + * Writes the QCC marker (quantization component) + * + * @param p_comp_no the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static void j2k_write_qcc_in_memory(opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_comp_no, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + struct opj_event_mgr * p_manager ); + +/** + * Gets the maximum size taken by a qcc. + */ +static OPJ_UINT32 j2k_get_max_qcc_size (opj_j2k_v2_t *p_j2k); + /** Read the QCC marker (quantization component) @param j2k J2K handle @@ -410,6 +708,36 @@ Write the POC marker (progression order change) @param j2k J2K handle */ static void j2k_write_poc(opj_j2k_t *j2k); + +/** + * Writes the POC marker (Progression Order Change) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. + */ +static void j2k_write_poc_in_memory(opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + struct opj_event_mgr * p_manager ); + +/** + * Gets the maximum size taken by the writting of a POC. + */ +static OPJ_UINT32 j2k_get_max_poc_size(opj_j2k_v2_t *p_j2k); + +/** + * Gets the maximum size taken by the toc headers of all the tile parts of any given tile. + */ +static OPJ_UINT32 j2k_get_max_toc_size (opj_j2k_v2_t *p_j2k); + +/** + * Gets the maximum size taken by the headers of the SOT. + * + * @param p_j2k the jpeg2000 codec to use. + */ +static OPJ_UINT32 j2k_get_specific_header_sizes(opj_j2k_v2_t *p_j2k); + /** Read the POC marker (progression order change) @param j2k J2K handle @@ -429,6 +757,7 @@ static opj_bool j2k_read_poc_v2 ( OPJ_UINT32 p_header_size, struct opj_event_mgr * p_manager ); + /** Read the CRG marker (component registration) @param j2k J2K handle @@ -467,6 +796,18 @@ static opj_bool j2k_read_tlm_v2 ( OPJ_UINT32 p_header_size, struct opj_event_mgr * p_manager ); + +/** + * Writes the updated tlm. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_updated_tlm( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + /** Read the PLM marker (packet length, main header) @param j2k J2K handle @@ -568,6 +909,19 @@ Read the SOT marker (start of tile-part) */ static void j2k_read_sot(opj_j2k_t *j2k); +/** + * Writes the SOT marker (Start of tile-part) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_sot_v2( opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + const struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + /** * Reads a PPT marker (Packed packet headers, tile-part header) * @@ -588,6 +942,22 @@ Write the SOD marker (start of data) @param tile_coder Pointer to a TCD handle */ static void j2k_write_sod(opj_j2k_t *j2k, void *tile_coder); + +/** + * Writes the SOD marker (Start of data) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_sod_v2( opj_j2k_v2_t *p_j2k, + struct opj_tcd_v2 * p_tile_coder, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 p_total_data_size, + const struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + /** Read the SOD marker (start of data) @param j2k J2K handle @@ -608,6 +978,18 @@ static opj_bool j2k_read_sod_v2 ( struct opj_event_mgr * p_manager ); +/** + * Updates the Tile Length Marker. + */ +void j2k_update_tlm (opj_j2k_v2_t * p_j2k, OPJ_UINT32 p_tile_part_size ) +{ + opj_write_bytes(p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current,p_j2k->m_current_tile_number,1); /* PSOT */ + ++p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current; + + opj_write_bytes(p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current,p_tile_part_size,4); /* PSOT */ + p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current += 4; +} + /** Write the RGN marker (region-of-interest) @param j2k J2K handle @@ -615,6 +997,22 @@ Write the RGN marker (region-of-interest) @param tileno Number of the tile concerned by the information written */ static void j2k_write_rgn(opj_j2k_t *j2k, int compno, int tileno); + +/** + * Writes the RGN marker (Region Of Interest) + * + * @param p_tile_no the tile to output + * @param p_comp_no the component to output + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_rgn_v2( opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + /** Read the RGN marker (region-of-interest) @param j2k J2K handle @@ -661,6 +1059,30 @@ static opj_bool j2k_read_eoc_v2 ( struct opj_event_mgr * p_manager ) ; + + +/** + * Writes the CBD-MCT-MCC-MCO markers (Multi components transform) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_mct_data_group( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + +/** + * Inits the Info + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_init_info( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + /** Read an unknown marker @param j2k J2K handle @@ -702,6 +1124,18 @@ static opj_bool j2k_read_unk_v2 ( opj_j2k_v2_t *p_j2k, OPJ_UINT32 *output_marker, struct opj_event_mgr * p_manager ); +/** + * Writes the MCT marker (Multiple Component Transform) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_mct_record( opj_j2k_v2_t *p_j2k, + opj_mct_data_t * p_mct_record, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + /** * Reads a MCT marker (Multiple Component Transform) * @@ -715,6 +1149,19 @@ static opj_bool j2k_read_mct ( opj_j2k_v2_t *p_j2k, OPJ_UINT32 p_header_size, struct opj_event_mgr * p_manager ); +/** + * Writes the MCC marker (Multiple Component Collection) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_mcc_record( opj_j2k_v2_t *p_j2k, + struct opj_simple_mcc_decorrelation_data * p_mcc_record, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + + /** * Reads a MCC marker (Multiple Component Collection) * @@ -724,9 +1171,20 @@ static opj_bool j2k_read_mct ( opj_j2k_v2_t *p_j2k, * @param p_manager the user event manager. */ static opj_bool j2k_read_mcc ( opj_j2k_v2_t *p_j2k, - OPJ_BYTE * p_header_data, - OPJ_UINT32 p_header_size, - struct opj_event_mgr * p_manager ); + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager ); + +/** + * Writes the MCO marker (Multiple component transformation ordering) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_mco( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); /** * Reads a MCO marker (Multiple Component Transform Ordering) @@ -758,6 +1216,29 @@ static void j2k_write_float_to_int32 (const void * p_src_data, void * p_dest_da static void j2k_write_float_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem); static void j2k_write_float_to_float64 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem); + +/** + * Ends the encoding, i.e. frees memory. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_end_encoding( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + +/** + * Writes the CBD marker (Component bit depth definition) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_cbd( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + /** * Reads a CBD marker (Component bit depth definition) * @param p_header_data the data contained in the CBD box. @@ -770,6 +1251,67 @@ static opj_bool j2k_read_cbd ( opj_j2k_v2_t *p_j2k, OPJ_UINT32 p_header_size, struct opj_event_mgr * p_manager); +/** + * Writes the image components. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_image_components( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + +/** + * Writes regions of interests. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_regions( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + +/** + * Writes EPC ???? + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static opj_bool j2k_write_epc( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + +/** + * Gets the number of tile parts used for the given change of progression (if any) and the given tile. + * + * @param cp the coding parameters. + * @param pino the offset of the given poc (i.e. its position in the coding parameter). + * @param tileno the given tile. + * + * @return the number of tile parts. + */ +static OPJ_UINT32 j2k_get_num_tp_v2( opj_cp_v2_t *cp, OPJ_UINT32 pino, OPJ_UINT32 tileno); + +/** + * Calculates the total number of tile parts needed by the encoder to + * encode such an image. If not enough memory is available, then the function return false. + * + * @param p_nb_tiles pointer that will hold the number of tile parts. + * @param cp the coding parameters for the image. + * @param image the image to encode. + * @param p_j2k the p_j2k encoder. + * @param p_manager the user event manager. + * + * @return true if the function was successful, false else. + */ +static opj_bool j2k_calculate_tp_v2(opj_j2k_v2_t *p_j2k, + opj_cp_v2_t *cp, + OPJ_UINT32 * p_nb_tiles, + opj_image_t *image, + opj_event_mgr_t * p_manager); static void j2k_dump_MH_info(opj_j2k_v2_t* p_j2k, FILE* out_stream); @@ -1158,6 +1700,73 @@ static int j2k_get_num_tp(opj_cp_t *cp,int pino,int tileno){ return tpnum; } +/** + * Gets the number of tile parts used for the given change of progression (if any) and the given tile. + * + * @param cp the coding parameters. + * @param pino the offset of the given poc (i.e. its position in the coding parameter). + * @param tileno the given tile. + * + * @return the number of tile parts. + */ +OPJ_UINT32 j2k_get_num_tp_v2(opj_cp_v2_t *cp, OPJ_UINT32 pino, OPJ_UINT32 tileno) +{ + const OPJ_CHAR *prog = 00; + OPJ_UINT32 i; + OPJ_UINT32 tpnum = 1; + opj_tcp_v2_t *tcp = 00; + opj_poc_t * l_current_poc = 00; + + /* preconditions */ + assert(tileno < (cp->tw * cp->th)); + assert(pino < (cp->tcps[tileno].numpocs + 1)); + + /* get the given tile coding parameter */ + tcp = &cp->tcps[tileno]; + assert(tcp != 00); + + l_current_poc = &(tcp->pocs[pino]); + assert(l_current_poc != 0); + + /* get the progression order as a character string */ + prog = j2k_convert_progression_order(tcp->prg); + assert(strlen(prog) > 0); + + if (cp->m_specific_param.m_enc.m_tp_on == 1) { + for (i=0;i<4;++i) { + switch (prog[i]) + { + /* component wise */ + case 'C': + tpnum *= l_current_poc->compE; + break; + /* resolution wise */ + case 'R': + tpnum *= l_current_poc->resE; + break; + // precinct wise + case 'P': + tpnum *= l_current_poc->prcE; + break; + /* layer wise */ + case 'L': + tpnum *= l_current_poc->layE; + break; + } + /* whould we split here ? */ + if ( cp->m_specific_param.m_enc.m_tp_flag == prog[i] ) { + cp->m_specific_param.m_enc.m_tp_pos=i; + break; + } + } + } + else { + tpnum=1; + } + + return tpnum; +} + /** mem allocation for TLM marker*/ int j2k_calculate_tp(opj_cp_t *cp,int img_numcomp,opj_image_t *image,opj_j2k_t *j2k ){ int pino,tileno,totnum_tp=0; @@ -1188,6 +1797,95 @@ int j2k_calculate_tp(opj_cp_t *cp,int img_numcomp,opj_image_t *image,opj_j2k_t * return totnum_tp; } +/** + * Calculates the total number of tile parts needed by the encoder to + * encode such an image. If not enough memory is available, then the function return false. + * + * @param p_nb_tiles pointer that will hold the number of tile parts. + * @param cp the coding parameters for the image. + * @param image the image to encode. + * @param p_j2k the p_j2k encoder. + * @param p_manager the user event manager. + * + * @return true if the function was successful, false else. + */ +opj_bool j2k_calculate_tp_v2( opj_j2k_v2_t *p_j2k, + opj_cp_v2_t *cp, + OPJ_UINT32 * p_nb_tiles, + opj_image_t *image, + opj_event_mgr_t * p_manager) +{ + OPJ_UINT32 pino,tileno; + OPJ_UINT32 l_nb_tiles; + opj_tcp_v2_t *tcp; + + /* preconditions */ + assert(p_nb_tiles != 00); + assert(cp != 00); + assert(image != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + l_nb_tiles = cp->tw * cp->th; + * p_nb_tiles = 0; + tcp = cp->tcps; + + /* INDEX >> */ + /* TODO mergeV2: check this part which use cstr_info */ + /*if (p_j2k->cstr_info) { + opj_tile_info_t * l_info_tile_ptr = p_j2k->cstr_info->tile; + + for (tileno = 0; tileno < l_nb_tiles; ++tileno) { + OPJ_UINT32 cur_totnum_tp = 0; + + pi_update_encoding_parameters(image,cp,tileno); + + for (pino = 0; pino <= tcp->numpocs; ++pino) + { + OPJ_UINT32 tp_num = j2k_get_num_tp_v2(cp,pino,tileno); + + *p_nb_tiles = *p_nb_tiles + tp_num; + + cur_totnum_tp += tp_num; + } + + tcp->m_nb_tile_parts = cur_totnum_tp; + + l_info_tile_ptr->tp = (opj_tp_info_t *) opj_malloc(cur_totnum_tp * sizeof(opj_tp_info_t)); + if (l_info_tile_ptr->tp == 00) { + return OPJ_FALSE; + } + + memset(l_info_tile_ptr->tp,0,cur_totnum_tp * sizeof(opj_tp_info_t)); + + l_info_tile_ptr->num_tps = cur_totnum_tp; + + ++l_info_tile_ptr; + ++tcp; + } + } + else */{ + for (tileno = 0; tileno < l_nb_tiles; ++tileno) { + OPJ_UINT32 cur_totnum_tp = 0; + + pi_update_encoding_parameters(image,cp,tileno); + + for (pino = 0; pino <= tcp->numpocs; ++pino) { + OPJ_UINT32 tp_num = j2k_get_num_tp_v2(cp,pino,tileno); + + *p_nb_tiles = *p_nb_tiles + tp_num; + + cur_totnum_tp += tp_num; + } + tcp->m_nb_tile_parts = cur_totnum_tp; + + ++tcp; + } + } + + return OPJ_TRUE; +} + static void j2k_write_soc(opj_j2k_t *j2k) { opj_cio_t *cio = j2k->cio; cio_write(cio, J2K_MS_SOC, 2); @@ -1204,6 +1902,44 @@ static void j2k_write_soc(opj_j2k_t *j2k) { /* <m_specific_param.m_encoder.m_header_tile_data; + + /* write SOC identifier */ + opj_write_bytes(l_start_stream,J2K_MS_SOC,2); + + if (opj_stream_write_data(p_stream,l_start_stream,2,p_manager) != 2) { + return OPJ_FALSE; + } + +/* UniPG>> */ +#ifdef USE_JPWL + /* update markers struct */ + j2k_add_marker(p_j2k->cstr_info, J2K_MS_SOC, p_stream_tell(p_stream) - 2, 2); +#endif /* USE_JPWL */ +/* <state = J2K_STATE_MHSIZ; /* Index */ @@ -1290,6 +2026,107 @@ static void j2k_write_siz(opj_j2k_t *j2k) { j2k_add_mhmarker(j2k->cstr_info, J2K_MS_SIZ, lenp, len); } +/** + * Writes the SIZ marker (image and tile size) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +opj_bool j2k_write_siz_v2( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) +{ + OPJ_UINT32 i; + OPJ_UINT32 l_size_len; + OPJ_BYTE * l_current_ptr; + opj_image_t * l_image = 00; + opj_cp_v2_t *cp = 00; + opj_image_comp_t * l_img_comp = 00; + + /* preconditions */ + assert(p_stream != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + l_image = p_j2k->m_private_image; + cp = &(p_j2k->m_cp); + l_size_len = 40 + 3 * l_image->numcomps; + l_img_comp = l_image->comps; + + if (l_size_len > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) { + + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = (OPJ_BYTE*)opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_size_len); + if (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) { + return OPJ_FALSE; + } + + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_size_len; + } + + l_current_ptr = p_j2k->m_specific_param.m_encoder.m_header_tile_data; + + /* write SOC identifier */ + opj_write_bytes(l_current_ptr,J2K_MS_SIZ,2); /* SIZ */ + l_current_ptr+=2; + + opj_write_bytes(l_current_ptr,l_size_len-2,2); /* L_SIZ */ + l_current_ptr+=2; + + opj_write_bytes(l_current_ptr, cp->rsiz, 2); /* Rsiz (capabilities) */ + l_current_ptr+=2; + + opj_write_bytes(l_current_ptr, l_image->x1, 4); /* Xsiz */ + l_current_ptr+=4; + + opj_write_bytes(l_current_ptr, l_image->y1, 4); /* Ysiz */ + l_current_ptr+=4; + + opj_write_bytes(l_current_ptr, l_image->x0, 4); /* X0siz */ + l_current_ptr+=4; + + opj_write_bytes(l_current_ptr, l_image->y0, 4); /* Y0siz */ + l_current_ptr+=4; + + opj_write_bytes(l_current_ptr, cp->tdx, 4); /* XTsiz */ + l_current_ptr+=4; + + opj_write_bytes(l_current_ptr, cp->tdy, 4); /* YTsiz */ + l_current_ptr+=4; + + opj_write_bytes(l_current_ptr, cp->tx0, 4); /* XT0siz */ + l_current_ptr+=4; + + opj_write_bytes(l_current_ptr, cp->ty0, 4); /* YT0siz */ + l_current_ptr+=4; + + opj_write_bytes(l_current_ptr, l_image->numcomps, 2); /* Csiz */ + l_current_ptr+=2; + + for (i = 0; i < l_image->numcomps; ++i) { + // TODO here with MCT ? + opj_write_bytes(l_current_ptr, l_img_comp->prec - 1 + (l_img_comp->sgnd << 7), 1); /* Ssiz_i */ + ++l_current_ptr; + + opj_write_bytes(l_current_ptr, l_img_comp->dx, 1); /* XRsiz_i */ + ++l_current_ptr; + + opj_write_bytes(l_current_ptr, l_img_comp->dy, 1); /* YRsiz_i */ + ++l_current_ptr; + + ++l_img_comp; + } + + if (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_size_len,p_manager) != l_size_len) { + return OPJ_FALSE; + } + + return OPJ_TRUE; +} + static void j2k_read_siz(opj_j2k_t *j2k) { int len, i; @@ -1971,6 +2808,84 @@ static void j2k_write_cod(opj_j2k_t *j2k) { } +/** + * Writes the COD marker (Coding style default) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +opj_bool j2k_write_cod_v2( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) +{ + opj_cp_v2_t *l_cp = 00; + opj_tcp_v2_t *l_tcp = 00; + OPJ_UINT32 l_code_size,l_remaining_size; + OPJ_BYTE * l_current_data = 00; + + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_cp = &(p_j2k->m_cp); + l_tcp = &l_cp->tcps[p_j2k->m_current_tile_number]; + l_code_size = 9 + j2k_get_SPCod_SPCoc_size(p_j2k,p_j2k->m_current_tile_number,0); + l_remaining_size = l_code_size; + + if (l_code_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = (OPJ_BYTE*)opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_code_size); + + if (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) { + return OPJ_FALSE; + } + + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_code_size; + } + + l_current_data = p_j2k->m_specific_param.m_encoder.m_header_tile_data; + + opj_write_bytes(l_current_data,J2K_MS_COD,2); /* COD */ + l_current_data += 2; + + opj_write_bytes(l_current_data,l_code_size-2,2); /* L_COD */ + l_current_data += 2; + + opj_write_bytes(l_current_data,l_tcp->csty,1); /* Scod */ + ++l_current_data; + + opj_write_bytes(l_current_data,l_tcp->prg,1); /* SGcod (A) */ + ++l_current_data; + + opj_write_bytes(l_current_data,l_tcp->numlayers,2); /* SGcod (B) */ + l_current_data+=2; + + opj_write_bytes(l_current_data,l_tcp->mct,1); /* SGcod (C) */ + ++l_current_data; + + l_remaining_size -= 9; + + if (! j2k_write_SPCod_SPCoc(p_j2k,p_j2k->m_current_tile_number,0,l_current_data,&l_remaining_size,p_manager)) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error writting COD marker\n"); + return OPJ_FALSE; + } + + if (l_remaining_size != 0) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error writting COD marker\n"); + return OPJ_FALSE; + } + + if (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_code_size,p_manager) != l_code_size) { + return OPJ_FALSE; + } + + return OPJ_TRUE; +} + static void j2k_read_cod(opj_j2k_t *j2k) { int len, i, pos; @@ -2117,7 +3032,131 @@ static void j2k_write_coc(opj_j2k_t *j2k, int compno) { cio_seek(cio, lenp + len); } -static void j2k_read_coc(opj_j2k_t *j2k) { +/** + * Writes the COC marker (Coding style component) + * + * @param p_comp_no the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +opj_bool j2k_write_coc_v2( opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_comp_no, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) +{ + OPJ_UINT32 l_coc_size,l_remaining_size; + OPJ_UINT32 l_comp_room; + + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_comp_room = (p_j2k->m_private_image->numcomps <= 256) ? 1 : 2; + + l_coc_size = 5 + l_comp_room + j2k_get_SPCod_SPCoc_size(p_j2k,p_j2k->m_current_tile_number,p_comp_no); + + if (l_coc_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = (OPJ_BYTE*)opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_coc_size); + if (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) { + return OPJ_FALSE; + } + + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_coc_size; + } + + j2k_write_coc_in_memory(p_j2k,p_comp_no,p_j2k->m_specific_param.m_encoder.m_header_tile_data,&l_remaining_size,p_manager); + + if (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_coc_size,p_manager) != l_coc_size) { + return OPJ_FALSE; + } + + return OPJ_TRUE; +} + +/** + * Writes the COC marker (Coding style component) + * + * @param p_comp_no the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +void j2k_write_coc_in_memory( opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_comp_no, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + struct opj_event_mgr * p_manager ) +{ + opj_cp_v2_t *l_cp = 00; + opj_tcp_v2_t *l_tcp = 00; + OPJ_UINT32 l_coc_size,l_remaining_size; + OPJ_BYTE * l_current_data = 00; + opj_image_t *l_image = 00; + OPJ_UINT32 l_comp_room; + + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + + l_cp = &(p_j2k->m_cp); + l_tcp = &l_cp->tcps[p_j2k->m_current_tile_number]; + l_image = p_j2k->m_private_image; + l_comp_room = (l_image->numcomps <= 256) ? 1 : 2; + + l_coc_size = 5 + l_comp_room + j2k_get_SPCod_SPCoc_size(p_j2k,p_j2k->m_current_tile_number,p_comp_no); + l_remaining_size = l_coc_size; + + l_current_data = p_data; + + opj_write_bytes(l_current_data,J2K_MS_COC,2); /* COC */ + l_current_data += 2; + + opj_write_bytes(l_current_data,l_coc_size-2,2); /* L_COC */ + l_current_data += 2; + + opj_write_bytes(l_current_data,p_comp_no, l_comp_room); /* Ccoc */ + l_current_data+=l_comp_room; + + opj_write_bytes(l_current_data, l_tcp->tccps[p_comp_no].csty, 1); /* Scoc */ + ++l_current_data; + + l_remaining_size -= (5 + l_comp_room); + j2k_write_SPCod_SPCoc(p_j2k,p_j2k->m_current_tile_number,0,l_current_data,&l_remaining_size,p_manager); + * p_data_written = l_coc_size; +} + +/** + * Gets the maximum size taken by a coc. + * + * @param p_j2k the jpeg2000 codec to use. + */ +OPJ_UINT32 j2k_get_max_coc_size(opj_j2k_v2_t *p_j2k) +{ + OPJ_UINT32 i,j; + OPJ_UINT32 l_nb_comp; + OPJ_UINT32 l_nb_tiles; + OPJ_UINT32 l_max = 0; + + /* preconditions */ + + l_nb_tiles = p_j2k->m_cp.tw * p_j2k->m_cp.th ; + l_nb_comp = p_j2k->m_private_image->numcomps; + + for (i=0;icp; @@ -2309,6 +3348,74 @@ static void j2k_write_qcd(opj_j2k_t *j2k) { j2k_add_mhmarker(j2k->cstr_info, J2K_MS_QCD, lenp, len); } +/** + * Writes the QCD marker (quantization default) + * + * @param p_comp_number the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +opj_bool j2k_write_qcd_v2( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) +{ + opj_cp_v2_t *l_cp = 00; + opj_tcp_v2_t *l_tcp = 00; + OPJ_UINT32 l_qcd_size,l_remaining_size; + OPJ_BYTE * l_current_data = 00; + + /* preconditions */ + assert(p_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_BYTE*)opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_qcd_size); + + if (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) { + return OPJ_FALSE; + } + + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_qcd_size; + } + + l_current_data = p_j2k->m_specific_param.m_encoder.m_header_tile_data; + + opj_write_bytes(l_current_data,J2K_MS_QCD,2); /* QCD */ + l_current_data += 2; + + opj_write_bytes(l_current_data,l_qcd_size-2,2); /* L_QCD */ + l_current_data += 2; + + l_remaining_size -= 4; + + if (! j2k_write_SQcd_SQcc(p_j2k,p_j2k->m_current_tile_number,0,l_current_data,&l_remaining_size,p_manager)) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error writting QCD marker\n"); + return OPJ_FALSE; + } + + if (l_remaining_size != 0) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error writting QCD marker\n"); + return OPJ_FALSE; + } + + if (opj_stream_write_data(p_stream, p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_qcd_size,p_manager) != l_qcd_size) { + return OPJ_FALSE; + } + + return OPJ_TRUE; +} + + static void j2k_read_qcd(opj_j2k_t *j2k) { int len, i, pos; @@ -2374,6 +3481,114 @@ static void j2k_write_qcc(opj_j2k_t *j2k, int compno) { cio_seek(cio, lenp + len); } +/** + * Writes the QCC marker (quantization component) + * + * @param p_comp_no the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +opj_bool j2k_write_qcc_v2( opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_comp_no, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) +{ + OPJ_UINT32 l_qcc_size,l_remaining_size; + + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_qcc_size = 6 + j2k_get_SQcd_SQcc_size(p_j2k,p_j2k->m_current_tile_number,p_comp_no); + l_remaining_size = l_qcc_size; + + if (l_qcc_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = (OPJ_BYTE*)opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_qcc_size); + if (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) { + return OPJ_FALSE; + } + + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_qcc_size; + } + + j2k_write_qcc_in_memory(p_j2k,p_comp_no,p_j2k->m_specific_param.m_encoder.m_header_tile_data,&l_remaining_size,p_manager); + + if (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_qcc_size,p_manager) != l_qcc_size) { + return OPJ_FALSE; + } + + return OPJ_TRUE; +} + +/** + * Writes the QCC marker (quantization component) + * + * @param p_comp_no the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +void j2k_write_qcc_in_memory( opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_comp_no, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + struct opj_event_mgr * p_manager ) +{ + OPJ_UINT32 l_qcc_size,l_remaining_size; + OPJ_BYTE * l_current_data = 00; + + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + + l_qcc_size = 6 + j2k_get_SQcd_SQcc_size(p_j2k,p_j2k->m_current_tile_number,p_comp_no); + l_remaining_size = l_qcc_size; + + l_current_data = p_data; + + opj_write_bytes(l_current_data,J2K_MS_QCC,2); /* QCC */ + l_current_data += 2; + + if (p_j2k->m_private_image->numcomps <= 256) { + --l_qcc_size; + + opj_write_bytes(l_current_data,l_qcc_size-2,2); /* L_QCC */ + l_current_data += 2; + + opj_write_bytes(l_current_data, p_comp_no, 1); /* Cqcc */ + ++l_current_data; + + /* in the case only one byte is sufficient the last byte allocated is useless -> still do -6 for available */ + l_remaining_size -= 6; + } + else { + opj_write_bytes(l_current_data,l_qcc_size-2,2); /* L_QCC */ + l_current_data += 2; + + opj_write_bytes(l_current_data, p_comp_no, 2); /* Cqcc */ + l_current_data+=2; + + l_remaining_size -= 6; + } + + j2k_write_SQcd_SQcc(p_j2k,p_j2k->m_current_tile_number,p_comp_no,l_current_data,&l_remaining_size,p_manager); + + *p_data_written = l_qcc_size; +} + +/** + * Gets the maximum size taken by a qcc. + */ +OPJ_UINT32 j2k_get_max_qcc_size (opj_j2k_v2_t *p_j2k) +{ + return j2k_get_max_coc_size(p_j2k); +} + static void j2k_read_qcc(opj_j2k_t *j2k) { int len, compno; int numcomp = j2k->image->numcomps; @@ -2519,100 +3734,256 @@ static void j2k_write_poc(opj_j2k_t *j2k) { } } -static void j2k_read_poc(opj_j2k_t *j2k) { - int len, numpchgs, i, old_poc; - - int numcomps = j2k->image->numcomps; - - 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; - - 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)); - - 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 */ - } - - tcp->numpocs = numpchgs + old_poc - 1; -} - /** - * Reads a POC marker (Progression Order Change) + * Writes the 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_stream the stream to write data to. + * @param p_j2k J2K codec. * @param p_manager the user event manager. */ -opj_bool j2k_read_poc_v2 ( - opj_j2k_v2_t *p_j2k, - OPJ_BYTE * p_header_data, - OPJ_UINT32 p_header_size, - struct opj_event_mgr * p_manager) +void j2k_write_poc_in_memory( opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + struct opj_event_mgr * p_manager ) { - OPJ_UINT32 i, l_nb_comp, l_tmp; - 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, l_comp_room; - - opj_cp_v2_t *l_cp = 00; + OPJ_UINT32 i; + OPJ_BYTE * l_current_data = 00; + OPJ_UINT32 l_nb_comp; + OPJ_UINT32 l_nb_poc; + OPJ_UINT32 l_poc_size; + opj_image_t *l_image = 00; opj_tcp_v2_t *l_tcp = 00; + opj_tccp_t *l_tccp = 00; opj_poc_t *l_current_poc = 00; + OPJ_UINT32 l_poc_room; /* preconditions */ - assert(p_header_data != 00); assert(p_j2k != 00); assert(p_manager != 00); + l_tcp = &p_j2k->m_cp.tcps[p_j2k->m_current_tile_number]; + l_tccp = &l_tcp->tccps[0]; l_image = p_j2k->m_private_image; l_nb_comp = l_image->numcomps; + l_nb_poc = 1 + l_tcp->numpocs; + if (l_nb_comp <= 256) { - l_comp_room = 1; + l_poc_room = 1; } else { - l_comp_room = 2; + l_poc_room = 2; } - l_chunk_size = 5 + 2 * l_comp_room; - l_current_poc_nb = p_header_size / l_chunk_size; - l_current_poc_remaining = p_header_size % l_chunk_size; - if ((l_current_poc_nb <= 0) || (l_current_poc_remaining != 0)) { - opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading POC marker\n"); - return OPJ_FALSE; - } + l_poc_size = 4 + (5 + 2 * l_poc_room) * l_nb_poc; - l_cp = &(p_j2k->m_cp); - l_tcp = (p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_TPH) ? - &l_cp->tcps[p_j2k->m_current_tile_number] : - p_j2k->m_specific_param.m_decoder.m_default_tcp; - l_old_poc_nb = l_tcp->POC ? l_tcp->numpocs + 1 : 0; - l_current_poc_nb += l_old_poc_nb; + l_current_data = p_data; - assert(l_current_poc_nb < 32); + opj_write_bytes(l_current_data,J2K_MS_POC,2); /* POC */ + l_current_data += 2; - /* now poc is in use.*/ - l_tcp->POC = 1; + opj_write_bytes(l_current_data,l_poc_size-2,2); /* Lpoc */ + l_current_data += 2; - 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; + l_current_poc = l_tcp->pocs; + for (i = 0; i < l_nb_poc; ++i) { + opj_write_bytes(l_current_data,l_current_poc->resno0,1); /* RSpoc_i */ + ++l_current_data; + + opj_write_bytes(l_current_data,l_current_poc->compno0,l_poc_room); /* CSpoc_i */ + l_current_data+=l_poc_room; + + opj_write_bytes(l_current_data,l_current_poc->layno1,2); /* LYEpoc_i */ + l_current_data+=2; + + opj_write_bytes(l_current_data,l_current_poc->resno1,1); /* REpoc_i */ + ++l_current_data; + + opj_write_bytes(l_current_data,l_current_poc->compno1,l_poc_room); /* CEpoc_i */ + l_current_data+=l_poc_room; + + opj_write_bytes(l_current_data,l_current_poc->prg,1); /* Ppoc_i */ + ++l_current_data; + + /* change the value of the max layer according to the actual number of layers in the file, components and resolutions*/ + l_current_poc->layno1 = int_min(l_current_poc->layno1, l_tcp->numlayers); + l_current_poc->resno1 = int_min(l_current_poc->resno1, l_tccp->numresolutions); + l_current_poc->compno1 = int_min(l_current_poc->compno1, l_nb_comp); + + ++l_current_poc; + } + + *p_data_written = l_poc_size; +} + +/** + * Gets the maximum size taken by the writing of a POC. + */ +OPJ_UINT32 j2k_get_max_poc_size(opj_j2k_v2_t *p_j2k) +{ + opj_tcp_v2_t * l_tcp = 00; + OPJ_UINT32 l_nb_tiles = 0; + OPJ_UINT32 l_max_poc = 0; + OPJ_UINT32 i; + + l_tcp = p_j2k->m_cp.tcps; + l_nb_tiles = p_j2k->m_cp.th * p_j2k->m_cp.tw; + + for (i=0;inumpocs); + ++l_tcp; + } + + ++l_max_poc; + + return 4 + 9 * l_max_poc; +} + +/** + * Gets the maximum size taken by the toc headers of all the tile parts of any given tile. + */ +OPJ_UINT32 j2k_get_max_toc_size (opj_j2k_v2_t *p_j2k) +{ + OPJ_UINT32 i; + OPJ_UINT32 l_nb_tiles; + OPJ_UINT32 l_max = 0; + opj_tcp_v2_t * l_tcp = 00; + + l_tcp = p_j2k->m_cp.tcps; + l_nb_tiles = p_j2k->m_cp.tw * p_j2k->m_cp.th ; + + for (i=0;im_nb_tile_parts); + + ++l_tcp; + } + + return 12 * l_max; +} + + +/** + * Gets the maximum size taken by the headers of the SOT. + * + * @param p_j2k the jpeg2000 codec to use. + */ +OPJ_UINT32 j2k_get_specific_header_sizes(opj_j2k_v2_t *p_j2k) +{ + OPJ_UINT32 l_nb_bytes = 0; + OPJ_UINT32 l_nb_comps; + OPJ_UINT32 l_coc_bytes,l_qcc_bytes; + + l_nb_comps = p_j2k->m_private_image->numcomps - 1; + l_nb_bytes += j2k_get_max_toc_size(p_j2k); + + if (p_j2k->m_cp.m_specific_param.m_enc.m_cinema == 0) { + l_coc_bytes = j2k_get_max_coc_size(p_j2k); + l_nb_bytes += l_nb_comps * l_coc_bytes; + + l_qcc_bytes = j2k_get_max_qcc_size(p_j2k); + l_nb_bytes += l_nb_comps * l_qcc_bytes; + } + + l_nb_bytes += j2k_get_max_poc_size(p_j2k); + + /*** DEVELOPER CORNER, Add room for your headers ***/ + + return l_nb_bytes; +} + +static void j2k_read_poc(opj_j2k_t *j2k) { + int len, numpchgs, i, old_poc; + + int numcomps = j2k->image->numcomps; + + 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; + + 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)); + + 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 */ + } + + tcp->numpocs = numpchgs + old_poc - 1; +} + +/** + * Reads a POC marker (Progression Order Change) + * + * @param p_header_data the data contained in the POC box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the POC marker. + * @param p_manager the user event manager. +*/ +opj_bool j2k_read_poc_v2 ( + opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager) +{ + OPJ_UINT32 i, l_nb_comp, l_tmp; + 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, l_comp_room; + + opj_cp_v2_t *l_cp = 00; + opj_tcp_v2_t *l_tcp = 00; + opj_poc_t *l_current_poc = 00; + + /* preconditions */ + assert(p_header_data != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + l_image = p_j2k->m_private_image; + l_nb_comp = l_image->numcomps; + if (l_nb_comp <= 256) { + l_comp_room = 1; + } + else { + l_comp_room = 2; + } + l_chunk_size = 5 + 2 * l_comp_room; + l_current_poc_nb = p_header_size / l_chunk_size; + l_current_poc_remaining = p_header_size % l_chunk_size; + + if ((l_current_poc_nb <= 0) || (l_current_poc_remaining != 0)) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading POC marker\n"); + return OPJ_FALSE; + } + + l_cp = &(p_j2k->m_cp); + l_tcp = (p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_TPH) ? + &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 */ @@ -3422,6 +4793,54 @@ static void j2k_write_sot(opj_j2k_t *j2k) { } } +/** + * Writes the SOT marker (Start of tile-part) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +opj_bool j2k_write_sot_v2( opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + const struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) +{ + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + opj_write_bytes(p_data,J2K_MS_SOT,2); /* SOT */ + p_data += 2; + + opj_write_bytes(p_data,10,2); /* Lsot */ + p_data += 2; + + opj_write_bytes(p_data, p_j2k->m_current_tile_number,2); /* Isot */ + p_data += 2; + + /* Psot */ + p_data += 4; + + opj_write_bytes(p_data, p_j2k->m_specific_param.m_encoder.m_current_tile_part_number,1); /* TPsot */ + ++p_data; + + opj_write_bytes(p_data, p_j2k->m_cp.tcps[p_j2k->m_current_tile_number].m_nb_tile_parts,1); /* TNsot */ + ++p_data; + + /* UniPG>> */ +#ifdef USE_JPWL + /* update markers struct */ + j2k_add_marker(p_j2k->cstr_info, J2K_MS_SOT, p_j2k->sot_start, len + 2); +#endif /* USE_JPWL */ + + * p_data_written = 12; + + return OPJ_TRUE; +} + + static void j2k_read_sot(opj_j2k_t *j2k) { int len, tileno, totlen, partno, numparts, i; opj_tcp_t *tcp = NULL; @@ -3860,6 +5279,95 @@ static void j2k_write_sod(opj_j2k_t *j2k, void *tile_coder) { cio_seek(cio, j2k->sot_start + totlen); } +/** + * Writes the SOD marker (Start of data) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +opj_bool j2k_write_sod_v2( opj_j2k_v2_t *p_j2k, + struct opj_tcd_v2 * p_tile_coder, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 p_total_data_size, + const struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) +{ + opj_tcp_v2_t *l_tcp = 00; + opj_codestream_info_t *l_cstr_info = 00; + opj_cp_v2_t *l_cp = 00; + + OPJ_UINT32 l_size_tile; + OPJ_UINT32 l_remaining_data; + + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + opj_write_bytes(p_data,J2K_MS_SOD,2); /* SOD */ + p_data += 2; + + /* make room for the EOF marker */ + l_remaining_data = p_total_data_size - 4; + + l_cp = &(p_j2k->m_cp); + l_tcp = &l_cp->tcps[p_j2k->m_current_tile_number]; + + + /* update tile coder */ + p_tile_coder->tp_num = p_j2k->m_specific_param.m_encoder.m_current_poc_tile_part_number ; + p_tile_coder->cur_tp_num = p_j2k->m_specific_param.m_encoder.m_current_tile_part_number; + + l_size_tile = l_cp->th * l_cp->tw; + + /* INDEX >> */ + /* TODO mergeV2: check this part which use cstr_info */ + /*l_cstr_info = p_j2k->cstr_info; + if (l_cstr_info) { + if (!p_j2k->m_specific_param.m_encoder.m_current_tile_part_number ) { + //TODO cstr_info->tile[p_j2k->m_current_tile_number].end_header = p_stream_tell(p_stream) + p_j2k->pos_correction - 1; + l_cstr_info->tile[p_j2k->m_current_tile_number].tileno = p_j2k->m_current_tile_number; + } + else {*/ + /* + TODO + if + (cstr_info->tile[p_j2k->m_current_tile_number].packet[cstr_info->packno - 1].end_pos < p_stream_tell(p_stream)) + { + cstr_info->tile[p_j2k->m_current_tile_number].packet[cstr_info->packno].start_pos = p_stream_tell(p_stream); + }*/ + /*}*/ + /* UniPG>> */ +#ifdef USE_JPWL + /* update markers struct */ + j2k_add_marker(p_j2k->cstr_info, J2K_MS_SOD, p_j2k->sod_start, 2); +#endif /* USE_JPWL */ + /* <m_specific_param.m_encoder.m_current_tile_part_number == 0) { + p_tile_coder->tcd_image->tiles->packno = 0; + if (l_cstr_info) { + l_cstr_info->packno = 0; + } + } + + *p_data_written = 0; + + if (! tcd_encode_tile_v2(p_tile_coder, p_j2k->m_current_tile_number, p_data, p_data_written, l_remaining_data , l_cstr_info)) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Cannot encode tile\n"); + return OPJ_FALSE; + } + + *p_data_written += 2; + + return OPJ_TRUE; +} + + static void j2k_read_sod(opj_j2k_t *j2k) { int len, truncate = 0, i; unsigned char *data = NULL, *data_ptr = NULL; @@ -4005,17 +5513,85 @@ static void j2k_write_rgn(opj_j2k_t *j2k, int compno, int tileno) { cio_write(cio, tcp->tccps[compno].roishift, 1); /* SPrgn */ } -static void j2k_read_rgn(opj_j2k_t *j2k) { - int len, compno, roisty; - - 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; +/** + * Writes the RGN marker (Region Of Interest) + * + * @param p_tile_no the tile to output + * @param p_comp_no the component to output + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +opj_bool j2k_write_rgn_v2( opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) +{ + OPJ_BYTE * l_current_data = 00; + OPJ_UINT32 l_nb_comp; + OPJ_UINT32 l_rgn_size; + opj_image_t *l_image = 00; + opj_cp_v2_t *l_cp = 00; + opj_tcp_v2_t *l_tcp = 00; + opj_tccp_t *l_tccp = 00; + OPJ_UINT32 l_comp_room; - len = cio_read(cio, 2); /* Lrgn */ - compno = cio_read(cio, numcomps <= 256 ? 1 : 2); /* Crgn */ - roisty = cio_read(cio, 1); /* Srgn */ + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_cp = &(p_j2k->m_cp); + l_tcp = &l_cp->tcps[p_tile_no]; + l_tccp = &l_tcp->tccps[p_comp_no]; + + l_nb_comp = l_image->numcomps; + + if (l_nb_comp <= 256) { + l_comp_room = 1; + } + else { + l_comp_room = 2; + } + + l_rgn_size = 6 + l_comp_room; + + l_current_data = p_j2k->m_specific_param.m_encoder.m_header_tile_data; + + opj_write_bytes(l_current_data,J2K_MS_RGN,2); /* RGN */ + l_current_data += 2; + + opj_write_bytes(l_current_data,l_rgn_size-2,2); /* Lrgn */ + l_current_data += 2; + + opj_write_bytes(l_current_data,p_comp_no,l_comp_room); /* Crgn */ + l_current_data+=l_comp_room; + + opj_write_bytes(l_current_data, 0,1); /* Srgn */ + ++l_current_data; + + opj_write_bytes(l_current_data, l_tccp->roishift,1); /* SPrgn */ + ++l_current_data; + + if (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_rgn_size,p_manager) != l_rgn_size) { + return OPJ_FALSE; + } + + return OPJ_TRUE; +} + +static void j2k_read_rgn(opj_j2k_t *j2k) { + int len, compno, roisty; + + 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; + + len = cio_read(cio, 2); /* Lrgn */ + compno = cio_read(cio, numcomps <= 256 ? 1 : 2); /* Crgn */ + roisty = cio_read(cio, 1); /* Srgn */ #ifdef USE_JPWL if (j2k->cp->correct) { @@ -4120,6 +5696,186 @@ opj_bool j2k_read_rgn_v2 ( } +OPJ_FLOAT32 get_tp_stride (opj_tcp_v2_t * p_tcp) +{ + return (OPJ_FLOAT32) ((p_tcp->m_nb_tile_parts - 1) * 14); +} + +OPJ_FLOAT32 get_default_stride (opj_tcp_v2_t * p_tcp) +{ + return 0; +} + +/** + * 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. +*/ +opj_bool j2k_update_rates( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) +{ + opj_cp_v2_t * l_cp = 00; + opj_image_t * l_image = 00; + opj_tcp_v2_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_v2_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_private_image; + l_tcp = l_cp->tcps; + + l_bits_empty = 8 * l_image->comps->dx * l_image->comps->dy; + l_size_pixel = l_image->numcomps * l_image->comps->prec; + l_sot_remove = ((OPJ_FLOAT32) opj_stream_tell(p_stream)) / (l_cp->th * l_cp->tw); + + if (l_cp->m_specific_param.m_enc.m_tp_on) { + l_tp_stride_func = get_tp_stride; + } + else { + l_tp_stride_func = get_default_stride; + } + + for (i=0;ith;++i) { + for (j=0;jtw;++j) { + OPJ_FLOAT32 l_offset = ((*l_tp_stride_func)(l_tcp)) / l_tcp->numlayers; + + /* 4 borders of the tile rescale on the image if necessary */ + l_x0 = int_max(l_cp->tx0 + j * l_cp->tdx, l_image->x0); + l_y0 = int_max(l_cp->ty0 + i * l_cp->tdy, l_image->y0); + l_x1 = int_min(l_cp->tx0 + (j + 1) * l_cp->tdx, l_image->x1); + l_y1 = int_min(l_cp->ty0 + (i + 1) * l_cp->tdy, l_image->y1); + + l_rates = l_tcp->rates; + + /* Modification of the RATE >> */ + if (*l_rates) { + *l_rates = (( (float) (l_size_pixel * (l_x1 - l_x0) * (l_y1 - l_y0))) + / + ((*l_rates) * l_bits_empty) + ) + - + l_offset; + } + + ++l_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; + + } + } + + l_tcp = l_cp->tcps; + + for (i=0;ith;++i) { + for (j=0;jtw;++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;inumcomps;++i) { + l_tile_size += ( uint_ceildiv(l_cp->tdx,l_img_comp->dx) + * + uint_ceildiv(l_cp->tdy,l_img_comp->dy) + * + l_img_comp->prec + ); + + ++l_img_comp; + } + + l_tile_size = (OPJ_UINT32) (l_tile_size * 0.1625); /* 1.3/8 = 0.1625 */ + + l_tile_size += j2k_get_specific_header_sizes(p_j2k); + + p_j2k->m_specific_param.m_encoder.m_encoded_tile_size = l_tile_size; + p_j2k->m_specific_param.m_encoder.m_encoded_tile_data = + (OPJ_BYTE *) opj_malloc(p_j2k->m_specific_param.m_encoder.m_encoded_tile_size); + if (p_j2k->m_specific_param.m_encoder.m_encoded_tile_data == 00) { + return OPJ_FALSE; + } + + if (l_cp->m_specific_param.m_enc.m_cinema) { + p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer = + (OPJ_BYTE *) opj_malloc(5*p_j2k->m_specific_param.m_encoder.m_total_tile_parts); + if (! p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer) { + return OPJ_FALSE; + } + + p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current = + p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer; + } + + return OPJ_TRUE; +} + static void j2k_read_eoc(opj_j2k_t *j2k) { int i, tileno; opj_bool success; @@ -4214,108 +5970,293 @@ opj_bool j2k_read_eoc_v2 ( opj_j2k_v2_t *p_j2k, return OPJ_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; +/** + * 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. +*/ +opj_bool j2k_get_end_header(opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) +{ + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); -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}, + p_j2k->cstr_index->main_head_end = opj_stream_tell(p_stream); -#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 */ + return OPJ_TRUE; +} - {0, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_unk} -}; +/** + * 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. +*/ +opj_bool j2k_write_mct_data_group( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) +{ + OPJ_UINT32 i; + opj_simple_mcc_decorrelation_data_t * l_mcc_record; + opj_mct_data_t * l_mct_record; + opj_tcp_v2_t * l_tcp; -static void j2k_read_unk(opj_j2k_t *j2k) { - opj_event_msg(j2k->cinfo, EVT_WARNING, "Unknown marker\n"); + /* preconditions */ + assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); -#ifdef USE_JPWL - if (j2k->cp->correct) { - int m = 0, id, i; - int min_id = 0, min_dist = 17, cur_dist = 0, tmp_id; - cio_seek(j2k->cio, cio_tell(j2k->cio) - 2); - id = cio_read(j2k->cio, 2); - opj_event_msg(j2k->cinfo, EVT_ERROR, - "JPWL: really don't know this marker %x\n", - id); - if (!JPWL_ASSUME) { - opj_event_msg(j2k->cinfo, EVT_ERROR, - "- possible synch loss due to uncorrectable codestream errors => giving up\n"); - return; - } - /* OK, activate this at your own risk!!! */ - /* we look for the marker at the minimum hamming distance from this */ - while (j2k_dec_mstab[m].id) { - - /* 1's where they differ */ - tmp_id = j2k_dec_mstab[m].id ^ id; + if (! j2k_write_cbd(p_j2k,p_stream,p_manager)) { + return OPJ_FALSE; + } - /* compute the hamming distance between our id and the current */ - cur_dist = 0; - for (i = 0; i < 16; i++) { - if ((tmp_id >> i) & 0x0001) { - cur_dist++; - } - } + l_tcp = &(p_j2k->m_cp.tcps[p_j2k->m_current_tile_number]); + l_mct_record = l_tcp->m_mct_records; - /* if current distance is smaller, set the minimum */ - if (cur_dist < min_dist) { - min_dist = cur_dist; - min_id = j2k_dec_mstab[m].id; - } - - /* jump to the next marker */ - m++; + for (i=0;im_nb_mct_records;++i) { + + if (! j2k_write_mct_record(p_j2k,l_mct_record,p_stream,p_manager)) { + return OPJ_FALSE; } - /* do we substitute the marker? */ - if (min_dist < JPWL_MAXIMUM_HAMMING) { - opj_event_msg(j2k->cinfo, EVT_ERROR, - "- marker %x is at distance %d from the read %x\n", - min_id, min_dist, id); - opj_event_msg(j2k->cinfo, EVT_ERROR, - "- trying to substitute in place and crossing fingers!\n"); - cio_seek(j2k->cio, cio_tell(j2k->cio) - 2); - cio_write(j2k->cio, min_id, 2); + ++l_mct_record; + } - /* rewind */ - cio_seek(j2k->cio, cio_tell(j2k->cio) - 2); + l_mcc_record = l_tcp->m_mcc_records; + + for (i=0;im_nb_mcc_records;++i) { + if (! j2k_write_mcc_record(p_j2k,l_mcc_record,p_stream,p_manager)) { + return OPJ_FALSE; } - }; + ++l_mcc_record; + } + + if (! j2k_write_mco(p_j2k,p_stream,p_manager)) { + return OPJ_FALSE; + } + + return OPJ_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. +*/ +opj_bool j2k_write_image_components(opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) +{ + OPJ_UINT32 compno; + + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + for (compno = 1; compno < p_j2k->m_private_image->numcomps; ++compno) + { + if (! j2k_write_coc_v2(p_j2k,compno,p_stream, p_manager)) { + return OPJ_FALSE; + } + + if (! j2k_write_qcc_v2(p_j2k,compno,p_stream, p_manager)) { + return OPJ_FALSE; + } + } + + return OPJ_TRUE; +} + +/** + * Writes regions of interests. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +opj_bool j2k_write_regions( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) +{ + OPJ_UINT32 compno; + const opj_tccp_t *l_tccp = 00; + + /* 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_private_image->numcomps; ++compno) { + if (l_tccp->roishift) { + + if (! j2k_write_rgn_v2(p_j2k,0,compno,p_stream,p_manager)) { + return OPJ_FALSE; + } + } + + ++l_tccp; + } + + return OPJ_TRUE; +} + +/** + * Writes EPC ???? + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +opj_bool j2k_write_epc( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) +{ + opj_codestream_index_t * l_cstr_index = 00; + + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_cstr_index = p_j2k->cstr_index; + if (l_cstr_index) { + l_cstr_index->codestream_size = opj_stream_tell(p_stream); + /* UniPG>> */ + /* The following adjustment is done to adjust the codestream size */ + /* if SOD is not at 0 in the buffer. Useful in case of JP2, where */ + /* the first bunch of bytes is not in the codestream */ + l_cstr_index->codestream_size -= l_cstr_index->main_head_start; + /* <epc_on) { + + /* encode according to JPWL */ + jpwl_encode(p_j2k, p_stream, image); + + } +#endif /* USE_JPWL */ + + return OPJ_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}, + +#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 */ + + {0, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_unk} +}; + +static void j2k_read_unk(opj_j2k_t *j2k) { + opj_event_msg(j2k->cinfo, EVT_WARNING, "Unknown marker\n"); + +#ifdef USE_JPWL + if (j2k->cp->correct) { + int m = 0, id, i; + int min_id = 0, min_dist = 17, cur_dist = 0, tmp_id; + cio_seek(j2k->cio, cio_tell(j2k->cio) - 2); + id = cio_read(j2k->cio, 2); + opj_event_msg(j2k->cinfo, EVT_ERROR, + "JPWL: really don't know this marker %x\n", + id); + if (!JPWL_ASSUME) { + opj_event_msg(j2k->cinfo, EVT_ERROR, + "- possible synch loss due to uncorrectable codestream errors => giving up\n"); + return; + } + /* OK, activate this at your own risk!!! */ + /* we look for the marker at the minimum hamming distance from this */ + while (j2k_dec_mstab[m].id) { + + /* 1's where they differ */ + tmp_id = j2k_dec_mstab[m].id ^ id; + + /* compute the hamming distance between our id and the current */ + cur_dist = 0; + for (i = 0; i < 16; i++) { + if ((tmp_id >> i) & 0x0001) { + cur_dist++; + } + } + + /* if current distance is smaller, set the minimum */ + if (cur_dist < min_dist) { + min_dist = cur_dist; + min_id = j2k_dec_mstab[m].id; + } + + /* jump to the next marker */ + m++; + } + + /* do we substitute the marker? */ + if (min_dist < JPWL_MAXIMUM_HAMMING) { + opj_event_msg(j2k->cinfo, EVT_ERROR, + "- marker %x is at distance %d from the read %x\n", + min_id, min_dist, id); + opj_event_msg(j2k->cinfo, EVT_ERROR, + "- trying to substitute in place and crossing fingers!\n"); + cio_seek(j2k->cio, cio_tell(j2k->cio) - 2); + cio_write(j2k->cio, min_id, 2); + + /* rewind */ + cio_seek(j2k->cio, cio_tell(j2k->cio) - 2); + + } + + }; #endif /* USE_JPWL */ } @@ -4399,6 +6340,70 @@ static opj_dec_mstabent_t *j2k_dec_mstab_lookup(int id) { return e; } +/** + * 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. +*/ +opj_bool j2k_write_mct_record( opj_j2k_v2_t *p_j2k, + opj_mct_data_t * p_mct_record, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) +{ + OPJ_UINT32 l_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_BYTE*)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 OPJ_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 OPJ_FALSE; + } + + return OPJ_TRUE; +} /** * Reads a MCT marker (Multiple Component Transform) @@ -4509,28 +6514,137 @@ opj_bool j2k_read_mct ( opj_j2k_v2_t *p_j2k, } /** - * Reads a MCC marker (Multiple Component Collection) + * Writes the 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_stream the stream to write data to. + * @param p_j2k J2K codec. * @param p_manager the user event manager. */ -opj_bool j2k_read_mcc ( opj_j2k_v2_t *p_j2k, - OPJ_BYTE * p_header_data, - OPJ_UINT32 p_header_size, - struct opj_event_mgr * p_manager ) +opj_bool j2k_write_mcc_record( opj_j2k_v2_t *p_j2k, + struct opj_simple_mcc_decorrelation_data * p_mcc_record, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) { - OPJ_UINT32 i,j; - OPJ_UINT32 l_tmp; - OPJ_UINT32 l_indix; - opj_tcp_v2_t * l_tcp; - opj_simple_mcc_decorrelation_data_t * l_mcc_record; - opj_mct_data_t * l_mct_data; - OPJ_UINT32 l_nb_collections; - OPJ_UINT32 l_nb_comps; - OPJ_UINT32 l_nb_bytes_by_comp; - + OPJ_UINT32 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_BYTE*)opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_mcc_size); + if (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) { + return OPJ_FALSE; + } + + 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;im_nb_comps;++i) { + opj_write_bytes(l_current_data,i,l_nb_bytes_for_comp); /* Cmccij Component offset*/ + l_current_data+=l_nb_bytes_for_comp; + } + + 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;im_nb_comps;++i) + { + opj_write_bytes(l_current_data,i,l_nb_bytes_for_comp); /* Wmccij Component offset*/ + l_current_data+=l_nb_bytes_for_comp; + } + + 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 OPJ_FALSE; + } + + return OPJ_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. +*/ +opj_bool j2k_read_mcc ( opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager ) +{ + OPJ_UINT32 i,j; + OPJ_UINT32 l_tmp; + OPJ_UINT32 l_indix; + opj_tcp_v2_t * l_tcp; + opj_simple_mcc_decorrelation_data_t * l_mcc_record; + opj_mct_data_t * l_mct_data; + OPJ_UINT32 l_nb_collections; + OPJ_UINT32 l_nb_comps; + OPJ_UINT32 l_nb_bytes_by_comp; + /* preconditions */ assert(p_header_data != 00); @@ -4726,6 +6840,72 @@ opj_bool j2k_read_mcc ( opj_j2k_v2_t *p_j2k, return OPJ_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. +*/ +opj_bool j2k_write_mco( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_BYTE * l_current_data = 00; + OPJ_UINT32 l_mco_size; + opj_tcp_v2_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_BYTE*)opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_mco_size); + if (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) + { + return OPJ_FALSE; + } + + 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;im_nb_mcc_records;++i) { + opj_write_bytes(l_current_data,l_mcc_record->m_index,1); /* Imco -> use the mcc indicated by 1*/ + ++l_current_data; + + ++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 OPJ_FALSE; + } + + return OPJ_TRUE; +} + /** * Reads a MCO marker (Multiple Component Transform Ordering) * @@ -4881,6 +7061,71 @@ opj_bool j2k_add_mct(opj_tcp_v2_t * p_tcp, opj_image_t * p_image, OPJ_UINT32 p_i return OPJ_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. +*/ +opj_bool j2k_write_cbd( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) +{ + OPJ_UINT32 i; + OPJ_UINT32 l_cbd_size; + OPJ_BYTE * l_current_data = 00; + opj_image_t *l_image = 00; + opj_image_comp_t * l_comp = 00; + + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_image = p_j2k->m_private_image; + l_cbd_size = 6 + p_j2k->m_private_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_BYTE*)opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_cbd_size); + + if (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) { + return OPJ_FALSE; + } + + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_cbd_size; + } + + 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;inumcomps;++i) { + opj_write_bytes(l_current_data, (l_comp->sgnd << 7) | (l_comp->prec - 1), 1); /* Component bit depth */ + ++l_current_data; + + ++l_comp; + } + + if (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_cbd_size,p_manager) != l_cbd_size) { + return OPJ_FALSE; + } + + return OPJ_TRUE; +} + /** * Reads a CBD marker (Component bit depth definition) * @param p_header_data the data contained in the CBD box. @@ -5957,20 +8202,117 @@ void j2k_setup_decoding_validation (opj_j2k_v2_t *p_j2k) } + +/** + * The mct encoding validation procedure. + * + * @param p_j2k the jpeg2000 codec to validate. + * @param p_stream the input stream to validate. + * @param p_manager the user event manager. + * + * @return true if the parameters are correct. + */ +opj_bool j2k_mct_validation ( opj_j2k_v2_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ) +{ + opj_bool l_is_valid = OPJ_TRUE; + OPJ_UINT32 i,j; + + /* preconditions */ + assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); + + if ((p_j2k->m_cp.rsiz & 0x8200) == 0x8200) { + OPJ_UINT32 l_nb_tiles = p_j2k->m_cp.th * p_j2k->m_cp.tw; + opj_tcp_v2_t * l_tcp = p_j2k->m_cp.tcps; + + for (i=0;imct == 2) { + opj_tccp_t * l_tccp = l_tcp->tccps; + l_is_valid &= (l_tcp->m_mct_coding_matrix != 00); + + for (j=0;jm_private_image->numcomps;++j) { + l_is_valid &= ! (l_tccp->qmfbid & 1); + ++l_tccp; + } + } + ++l_tcp; + } + } + + return l_is_valid; +} + /** * Builds the cp decoder parameters to use to decode tile. */ -opj_bool j2k_build_decoder ( - opj_j2k_v2_t * p_j2k, - opj_stream_private_t *p_stream, - opj_event_mgr_t * p_manager - ) +opj_bool j2k_build_decoder (opj_j2k_v2_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ) +{ + /* add here initialization of cp + copy paste of setup_decoder */ + return OPJ_TRUE; +} + +/** + * Builds the cp encoder parameters to use to encode tile. + */ +opj_bool j2k_build_encoder (opj_j2k_v2_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ) { /* add here initialization of cp - // copy paste of setup_decoder*/ + copy paste of setup_encoder */ return OPJ_TRUE; } +/** + * The default encoding validation procedure without any extension. + * + * @param p_j2k the jpeg2000 codec to validate. + * @param p_stream the input stream to validate. + * @param p_manager the user event manager. + * + * @return true if the parameters are correct. + */ +opj_bool j2k_encoding_validation ( opj_j2k_v2_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ) +{ + opj_bool l_is_valid = OPJ_TRUE; + + /* preconditions */ + assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); + + /* STATE checking */ + /* make sure the state is at 0 */ + l_is_valid &= (p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_NONE); + + /* POINTER validation */ + /* make sure a p_j2k codec is present */ + l_is_valid &= (p_j2k->m_procedure_list != 00); + /* make sure a validation list is present */ + l_is_valid &= (p_j2k->m_validation_list != 00); + + if ((p_j2k->m_cp.tdx) < (OPJ_UINT32) (1 << p_j2k->m_cp.tcps->tccps->numresolutions)) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Number of resolutions is too high in comparison to the size of tiles\n"); + return OPJ_FALSE; + } + + if ((p_j2k->m_cp.tdy) < (OPJ_UINT32) (1 << p_j2k->m_cp.tcps->tccps->numresolutions)) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Number of resolutions is too high in comparison to the size of tiles\n"); + return OPJ_FALSE; + } + + /* PARAMETER VALIDATION */ + return l_is_valid; +} + /** * The default decoding validation procedure without any extension. * @@ -7359,30 +9701,142 @@ opj_codestream_index_t* j2k_create_cstr_index(void) return cstr_index; } + /** - * Reads a SPCod or SPCoc element, i.e. the coding style of a given component of a tile. - * @param p_header_data the data contained in the COM box. - * @param p_j2k the jpeg2000 codec. - * @param p_header_size the size of the data contained in the COM marker. - * @param p_manager the user event manager. -*/ -opj_bool j2k_read_SPCod_SPCoc( - opj_j2k_v2_t *p_j2k, - OPJ_UINT32 compno, - OPJ_BYTE * p_header_data, - OPJ_UINT32 * p_header_size, - struct opj_event_mgr * p_manager - ) + * Gets the size taken by writing a SPCod or SPCoc for the given tile and component. + * + * @param p_tile_no the tile index. + * @param p_comp_no the component being outputted. + * @param p_j2k the J2K codec. + * + * @return the number of bytes taken by the SPCod element. + */ +OPJ_UINT32 j2k_get_SPCod_SPCoc_size ( opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no ) { - OPJ_UINT32 i, l_tmp; - opj_cp_v2_t *l_cp = NULL; - opj_tcp_v2_t *l_tcp = NULL; - opj_tccp_t *l_tccp = NULL; - OPJ_BYTE * l_current_ptr = NULL; + opj_cp_v2_t *l_cp = 00; + opj_tcp_v2_t *l_tcp = 00; + opj_tccp_t *l_tccp = 00; /* preconditions */ assert(p_j2k != 00); - assert(p_manager != 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_private_image->numcomps); + + if (l_tccp->csty & J2K_CCP_CSTY_PRT) { + return 5 + l_tccp->numresolutions; + } + else { + return 5; + } +} + +/** + * Writes a SPCod or SPCoc element, i.e. the coding style of a given component of a tile. + * + * @param p_comp_no the component number to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. + * +*/ +opj_bool j2k_write_SPCod_SPCoc( opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_header_size, + struct opj_event_mgr * p_manager ) +{ + OPJ_UINT32 i; + opj_cp_v2_t *l_cp = 00; + opj_tcp_v2_t *l_tcp = 00; + opj_tccp_t *l_tccp = 00; + + /* 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_private_image->numcomps)); + + if (*p_header_size < 5) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error writing SPCod SPCoc element\n"); + return OPJ_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_v2(p_manager, EVT_ERROR, "Error writting SPCod SPCoc element\n"); + return OPJ_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 OPJ_TRUE; +} + +/** + * Reads a SPCod or SPCoc element, i.e. the coding style of a given component of a tile. + * @param p_header_data the data contained in the COM box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the COM marker. + * @param p_manager the user event manager. +*/ +opj_bool j2k_read_SPCod_SPCoc( + opj_j2k_v2_t *p_j2k, + OPJ_UINT32 compno, + OPJ_BYTE * p_header_data, + OPJ_UINT32 * p_header_size, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 i, l_tmp; + opj_cp_v2_t *l_cp = NULL; + opj_tcp_v2_t *l_tcp = NULL; + opj_tccp_t *l_tccp = NULL; + OPJ_BYTE * l_current_ptr = NULL; + + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); assert(p_header_data != 00); l_cp = &(p_j2k->m_cp); @@ -7513,6 +9967,130 @@ void j2k_copy_tile_component_parameters( opj_j2k_v2_t *p_j2k ) } } +/** + * Gets the size taken by writing SQcd or SQcc element, i.e. the quantization values of a band in the QCD or QCC. + * + * @param p_tile_no the tile index. + * @param p_comp_no the component being outputted. + * @param p_j2k the J2K codec. + * + * @return the number of bytes taken by the SPCod element. + */ +OPJ_UINT32 j2k_get_SQcd_SQcc_size ( opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no ) +{ + OPJ_UINT32 l_num_bands; + + opj_cp_v2_t *l_cp = 00; + opj_tcp_v2_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_private_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) { + return 1 + l_num_bands; + } + else { + return 1 + 2*l_num_bands; + } +} + +/** + * Writes a SQcd or SQcc element, i.e. the quantization values of a band. + * + * @param p_tile_no the tile to output. + * @param p_comp_no the component number to output. + * @param p_data the data buffer. + * @param p_header_size pointer to the size of the data buffer, it is changed by the function. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. + * +*/ +opj_bool j2k_write_SQcd_SQcc( opj_j2k_v2_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_header_size, + struct opj_event_mgr * p_manager ) +{ + OPJ_UINT32 l_header_size; + OPJ_UINT32 l_band_no, l_num_bands; + OPJ_UINT32 l_expn,l_mant; + + opj_cp_v2_t *l_cp = 00; + opj_tcp_v2_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 m_private_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_v2(p_manager, EVT_ERROR, "Error writing SQcd SQcc element\n"); + return OPJ_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_v2(p_manager, EVT_ERROR, "Error writing SQcd SQcc element\n"); + return OPJ_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 OPJ_TRUE; +} + /** * Reads a SQcd or SQcc element, i.e. the quantization values of a band. * @@ -8517,3 +11095,794 @@ opj_bool j2k_set_decoded_resolution_factor(opj_j2k_v2_t *p_j2k, OPJ_UINT32 res_f return OPJ_FALSE; } + + +/** + * Encodes all the tiles in a row. + */ +opj_bool j2k_encode_v2( opj_j2k_v2_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_BYTE*)opj_malloc(1000); + if (! l_current_data) { + return OPJ_FALSE; + } + l_max_tile_size = 1000; + + l_nb_tiles = p_j2k->m_cp.th * p_j2k->m_cp.tw; + for (i=0;im_tcd); + if (l_current_tile_size > l_max_tile_size) { + l_current_data = (OPJ_BYTE*)opj_realloc(l_current_data,l_current_tile_size); + if (! l_current_data) { + return OPJ_FALSE; + } + l_max_tile_size = l_current_tile_size; + } + + j2k_get_tile_data(p_j2k->m_tcd,l_current_data); + + if (! j2k_post_write_tile (p_j2k,l_current_data,l_current_tile_size,p_stream,p_manager)) { + return OPJ_FALSE; + } + } + + opj_free(l_current_data); + return OPJ_TRUE; +} + +/** + * Ends the compression procedures and possibility add data to be read after the + * codestream. + */ +opj_bool j2k_end_compress( opj_j2k_v2_t *p_j2k, + opj_stream_private_t *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 OPJ_FALSE; + } + + return OPJ_TRUE; +} + + +/** + * 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. + */ +opj_bool j2k_start_compress(opj_j2k_v2_t *p_j2k, + opj_stream_private_t *p_stream, + opj_image_t * p_image, + opj_event_mgr_t * p_manager) +{ + // preconditions + assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); + + p_j2k->m_private_image = p_image; + + /* 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 OPJ_FALSE; + } + + /* customization of the encoding */ + j2k_setup_header_writting(p_j2k); + + /* write header */ + if (! j2k_exec (p_j2k,p_j2k->m_procedure_list,p_stream,p_manager)) { + return OPJ_FALSE; + } + + return OPJ_TRUE; +} + +/* + * + */ +opj_bool j2k_pre_write_tile ( opj_j2k_v2_t * p_j2k, + OPJ_UINT32 p_tile_index, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ) +{ + if (p_tile_index != p_j2k->m_current_tile_number) { + opj_event_msg_v2(p_manager, EVT_ERROR, "The given tile index does not match." ); + return OPJ_FALSE; + } + + opj_event_msg_v2(p_manager, EVT_INFO, "tile number %d / %d\n", p_j2k->m_current_tile_number + 1, p_j2k->m_cp.tw * p_j2k->m_cp.th); + + p_j2k->m_specific_param.m_encoder.m_current_tile_part_number = 0; + p_j2k->m_tcd->cur_totnum_tp = p_j2k->m_cp.tcps[p_tile_index].m_nb_tile_parts; + p_j2k->m_specific_param.m_encoder.m_current_poc_tile_part_number = 0; + + /* initialisation before tile encoding */ + if (! tcd_init_encode_tile(p_j2k->m_tcd, p_j2k->m_current_tile_number)) { + return OPJ_FALSE; + } + + return OPJ_TRUE; +} + +/* + * + */ +void j2k_get_tile_data (opj_tcd_v2_t * p_tcd, OPJ_BYTE * p_data) +{ + OPJ_UINT32 i,j,k = 0; + OPJ_UINT32 l_width,l_height,l_stride, l_offset_x,l_offset_y, l_image_width; + opj_image_comp_t * l_img_comp = 00; + opj_tcd_tilecomp_v2_t * l_tilec = 00; + opj_image_t * l_image = 00; + OPJ_UINT32 l_size_comp, l_remaining; + OPJ_INT32 * l_src_ptr; + l_tilec = p_tcd->tcd_image->tiles->comps; + l_image = p_tcd->image; + l_img_comp = l_image->comps; + + for (i=0;iimage->numcomps;++i) { + l_size_comp = l_img_comp->prec >> 3; /* (/8) */ + l_remaining = l_img_comp->prec & 7; /* (%8) */ + if (l_remaining) { + ++l_size_comp; + } + + if (l_size_comp == 3) { + l_size_comp = 4; + } + + l_width = (l_tilec->x1 - l_tilec->x0); + l_height = (l_tilec->y1 - l_tilec->y0); + l_offset_x = int_ceildiv(l_image->x0, l_img_comp->dx); + l_offset_y = int_ceildiv(l_image->y0, l_img_comp->dy); + l_image_width = int_ceildiv(l_image->x1 - l_image->x0, l_img_comp->dx); + l_stride = l_image_width - l_width; + l_src_ptr = l_img_comp->data + (l_tilec->x0 - l_offset_x) + (l_tilec->y0 - l_offset_y) * l_image_width; + + switch (l_size_comp) { + case 1: + { + OPJ_CHAR * l_dest_ptr = (OPJ_CHAR*) p_data; + if (l_img_comp->sgnd) { + for (j=0;jsgnd) { + for (j=0;jm_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_v2(p_manager, EVT_ERROR, "Size mismtach between tile data and sent data." ); + return OPJ_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 OPJ_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 OPJ_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 OPJ_FALSE; + } + + ++p_j2k->m_current_tile_number; + + return OPJ_TRUE; +} + + +/** + * Sets up the validation ,i.e. adds the procedures to lauch to make sure the codec parameters + * are valid. Developers wanting to extend the library can add their own validation procedures. + */ +void j2k_setup_end_compress (opj_j2k_v2_t *p_j2k) +{ + /* preconditions */ + assert(p_j2k != 00); + + /* DEVELOPER CORNER, insert your custom procedures */ + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)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,(void*)j2k_write_updated_tlm); + } + + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_write_epc ); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_end_encoding ); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_destroy_header_memory); +} + +/** + * Sets up the validation ,i.e. adds the procedures to lauch to make sure the codec parameters + * are valid. Developers wanting to extend the library can add their own validation procedures. + */ +void j2k_setup_encoding_validation (opj_j2k_v2_t *p_j2k) +{ + /* preconditions */ + assert(p_j2k != 00); + + opj_procedure_list_add_procedure(p_j2k->m_validation_list, (void*)j2k_build_encoder); + opj_procedure_list_add_procedure(p_j2k->m_validation_list, (void*)j2k_encoding_validation); + + /* DEVELOPER CORNER, add your custom validation procedure */ + opj_procedure_list_add_procedure(p_j2k->m_validation_list, (void*)j2k_mct_validation); +} + + +/** + * Sets up the procedures to do on writing header. + * Developers wanting to extend the library can add their own writing procedures. + */ +void j2k_setup_header_writting (opj_j2k_v2_t *p_j2k) +{ + /* preconditions */ + assert(p_j2k != 00); + + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_init_info ); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_write_soc_v2 ); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_write_siz_v2 ); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_write_cod_v2 ); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_write_qcd_v2 ); + + + if (p_j2k->m_cp.m_specific_param.m_enc.m_cinema) { + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_write_image_components ); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)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,(void*)j2k_write_poc ); + } + } + + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_write_regions); + + if (p_j2k->m_cp.comment != 00) { + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)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,(void*)j2k_write_mct_data_group ); + } + /* End of Developer Corner */ + + if (p_j2k->cstr_index) { + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_get_end_header ); + } + + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_create_tcd); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_update_rates); +} + + +opj_bool j2k_write_first_tile_part (opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 p_total_data_size, + opj_stream_private_t *p_stream, + struct opj_event_mgr * p_manager ) +{ + OPJ_UINT32 compno; + OPJ_UINT32 l_nb_bytes_written = 0; + OPJ_UINT32 l_current_nb_bytes_written; + OPJ_BYTE * l_begin_data = 00; + + opj_tcp_v2_t *l_tcp = 00; + opj_tcd_v2_t * l_tcd = 00; + opj_cp_v2_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_v2(p_j2k,p_data,&l_current_nb_bytes_written,p_stream,p_manager)) + { + return OPJ_FALSE; + } + + l_nb_bytes_written += l_current_nb_bytes_written; + p_data += l_current_nb_bytes_written; + p_total_data_size -= l_current_nb_bytes_written; + + if (l_cp->m_specific_param.m_enc.m_cinema == 0) { + for (compno = 1; compno < p_j2k->m_private_image->numcomps; compno++) { + l_current_nb_bytes_written = 0; + j2k_write_coc_in_memory(p_j2k,compno,p_data,&l_current_nb_bytes_written,p_manager); + l_nb_bytes_written += l_current_nb_bytes_written; + p_data += l_current_nb_bytes_written; + p_total_data_size -= l_current_nb_bytes_written; + + l_current_nb_bytes_written = 0; + j2k_write_qcc_in_memory(p_j2k,compno,p_data,&l_current_nb_bytes_written,p_manager); + l_nb_bytes_written += l_current_nb_bytes_written; + p_data += l_current_nb_bytes_written; + p_total_data_size -= l_current_nb_bytes_written; + } + + 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_v2(p_j2k,l_tcd,p_data,&l_current_nb_bytes_written,p_total_data_size,p_stream,p_manager)) { + return OPJ_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 OPJ_TRUE; +} + +opj_bool j2k_write_all_tile_parts( opj_j2k_v2_t *p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 p_total_data_size, + opj_stream_private_t *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 tilepartno=0; + OPJ_UINT32 l_nb_bytes_written = 0; + OPJ_UINT32 l_current_nb_bytes_written; + OPJ_UINT32 l_part_tile_size; + OPJ_UINT32 tot_num_tp; + OPJ_UINT32 pino; + + OPJ_BYTE * l_begin_data; + opj_tcp_v2_t *l_tcp = 00; + opj_tcd_v2_t * l_tcd = 00; + opj_cp_v2_t * l_cp = 00; + + + 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_v2(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_v2(p_j2k,p_data,&l_current_nb_bytes_written,p_stream,p_manager)) { + return OPJ_FALSE; + } + + l_nb_bytes_written += l_current_nb_bytes_written; + p_data += l_current_nb_bytes_written; + p_total_data_size -= l_current_nb_bytes_written; + l_part_tile_size += l_nb_bytes_written; + + l_current_nb_bytes_written = 0; + if (! j2k_write_sod_v2(p_j2k,l_tcd,p_data,&l_current_nb_bytes_written,p_total_data_size,p_stream,p_manager)) { + return OPJ_FALSE; + } + + p_data += l_current_nb_bytes_written; + l_nb_bytes_written += l_current_nb_bytes_written; + p_total_data_size -= l_current_nb_bytes_written; + l_part_tile_size += l_nb_bytes_written; + + /* 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; + } + + for (pino = 1; pino <= l_tcp->numpocs; ++pino) { + l_tcd->cur_pino = pino; + + /*Get number of tile parts*/ + tot_num_tp = j2k_get_num_tp_v2(l_cp,pino,p_j2k->m_current_tile_number); + for (tilepartno = 0; tilepartno < tot_num_tp ; ++tilepartno) { + p_j2k->m_specific_param.m_encoder.m_current_poc_tile_part_number = tilepartno; + l_current_nb_bytes_written = 0; + l_part_tile_size = 0; + l_begin_data = p_data; + + if (! j2k_write_sot_v2(p_j2k,p_data,&l_current_nb_bytes_written,p_stream,p_manager)) { + return OPJ_FALSE; + } + + l_nb_bytes_written += l_current_nb_bytes_written; + p_data += l_current_nb_bytes_written; + p_total_data_size -= l_current_nb_bytes_written; + l_part_tile_size += l_current_nb_bytes_written; + + l_current_nb_bytes_written = 0; + + if (! j2k_write_sod_v2(p_j2k,l_tcd,p_data,&l_current_nb_bytes_written,p_total_data_size,p_stream,p_manager)) { + return OPJ_FALSE; + } + + 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 OPJ_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. +*/ +opj_bool j2k_write_updated_tlm( opj_j2k_v2_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 OPJ_FALSE; + } + + if (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer,l_tlm_size,p_manager) != l_tlm_size) { + return OPJ_FALSE; + } + + if (! opj_stream_seek(p_stream,l_current_position,p_manager)) { + return OPJ_FALSE; + } + + return OPJ_TRUE; +} + + +/** + * Ends the encoding, i.e. frees memory. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +opj_bool j2k_end_encoding( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) +{ + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + tcd_destroy_v2(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; + + return OPJ_TRUE; +} + +/** + * Destroys the memory associated with the decoding of headers. + */ +opj_bool j2k_destroy_header_memory (opj_j2k_v2_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ) +{ + /* preconditions */ + assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); + + if (p_j2k->m_specific_param.m_encoder.m_header_tile_data) { + opj_free(p_j2k->m_specific_param.m_encoder.m_header_tile_data); + p_j2k->m_specific_param.m_encoder.m_header_tile_data = 0; + } + + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = 0; + + return OPJ_TRUE; +} + + +/** + * Inits the Info + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +opj_bool j2k_init_info( opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) +{ + opj_codestream_info_t * l_cstr_info = 00; + + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + /* TODO mergeV2: check this part which use cstr_info */ + /*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; + }*/ + + return j2k_calculate_tp_v2(p_j2k,&(p_j2k->m_cp),&p_j2k->m_specific_param.m_encoder.m_total_tile_parts,p_j2k->m_private_image,p_manager); +} + +/** + * Creates a tile-coder decoder. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +opj_bool j2k_create_tcd(opj_j2k_v2_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) +{ + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + p_j2k->m_tcd = tcd_create_v2(OPJ_FALSE); + + if (! p_j2k->m_tcd) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Not enough memory to create Tile Coder\n"); + return OPJ_FALSE; + } + + if (! tcd_init_v2(p_j2k->m_tcd,p_j2k->m_private_image,&p_j2k->m_cp)) { + tcd_destroy_v2(p_j2k->m_tcd); + p_j2k->m_tcd = 00; + return OPJ_FALSE; + } + + return OPJ_TRUE; +} + + +/** + * Writes a tile. + * @param p_j2k the jpeg2000 codec. + * @param p_stream the stream to write data to. + * @param p_manager the user event manager. + */ +opj_bool j2k_write_tile (opj_j2k_v2_t * p_j2k, + OPJ_UINT32 p_tile_index, + OPJ_BYTE * p_data, + OPJ_UINT32 p_data_size, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ) +{ + if (! j2k_pre_write_tile(p_j2k,p_tile_index,p_stream,p_manager)) { + return OPJ_FALSE; + } + + return j2k_post_write_tile(p_j2k,p_data,p_data_size,p_stream,p_manager); +} diff --git a/libopenjpeg/j2k.h b/libopenjpeg/j2k.h index ae2f36f6..b31be140 100644 --- a/libopenjpeg/j2k.h +++ b/libopenjpeg/j2k.h @@ -107,6 +107,7 @@ The functions in J2K.C have for goal to read/write the several parts of the code * These values may be combined with a | operator. * */ typedef enum J2K_STATUS { + J2K_STATE_NONE = 0x0000, /**< a SOC marker is expected */ 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 */ @@ -1024,4 +1025,47 @@ opj_bool j2k_get_tile( opj_j2k_v2_t *p_j2k, opj_bool j2k_set_decoded_resolution_factor(opj_j2k_v2_t *p_j2k, OPJ_UINT32 res_factor, opj_event_mgr_t * 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. + */ +opj_bool j2k_write_tile ( opj_j2k_v2_t * p_j2k, + OPJ_UINT32 p_tile_index, + OPJ_BYTE * p_data, + OPJ_UINT32 p_data_size, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ); + +/** + * Encodes an image into a JPEG-2000 codestream + */ +opj_bool j2k_encode_v2( opj_j2k_v2_t * p_j2k, + opj_stream_private_t *cio, + struct opj_event_mgr * p_manager ); + +/** + * 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. + */ +opj_bool j2k_start_compress(opj_j2k_v2_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. + */ +opj_bool j2k_end_compress( opj_j2k_v2_t *p_j2k, + opj_stream_private_t *cio, + struct opj_event_mgr * p_manager); + + #endif /* __J2K_H */ diff --git a/libopenjpeg/jp2.c b/libopenjpeg/jp2.c index 841bc455..b0a2dcb3 100644 --- a/libopenjpeg/jp2.c +++ b/libopenjpeg/jp2.c @@ -132,6 +132,19 @@ static opj_bool jp2_read_ftyp_v2( struct opj_event_mgr * p_manager ); +/** + * 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. +*/ +opj_bool jp2_skip_jp2c( opj_jp2_v2_t *jp2, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager ); + /** * Reads the Jpeg2000 file Header box - JP2 Header box (warning, this is a super box). * @@ -286,6 +299,13 @@ static void write_prxy( int offset_jp2c, int length_jp2c, int offset_idx, int le /*@}*/ +/** + * 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_v2_t *jp2); + + /** * Sets up the procedures to do on reading header after the codestream. * Developpers wanting to extend the library can add their own writting procedures. @@ -350,6 +370,31 @@ static opj_bool jp2_read_boxhdr_v2( */ static const opj_jp2_header_handler_t * jp2_find_handler (int p_id ); +/** + * 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_v2_t *jp2); + + +/** + * 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_v2_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. + */ +opj_bool jp2_default_validation ( opj_jp2_v2_t * jp2, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager ); + /** * Finds the image execution function related to the given box id. * @@ -1980,9 +2025,47 @@ opj_bool jp2_end_decompress(opj_jp2_v2_t *jp2, opj_stream_private_t *cio, opj_ev return j2k_end_decompress(jp2->j2k, cio, p_manager); } +/** + * Ends the compression procedures and possibility add data to be read after the + * codestream. + */ +opj_bool jp2_end_compress( opj_jp2_v2_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 OPJ_FALSE; + } + + /* write header */ + return jp2_exec(jp2,jp2->m_procedure_list,cio,p_manager); +} + + +/** + * Sets up the procedures to do on writing header after the codestream. + * Developers wanting to extend the library can add their own writing procedures. + */ +void jp2_setup_end_header_writting (opj_jp2_v2_t *jp2) +{ + /* preconditions */ + assert(jp2 != 00); + + opj_procedure_list_add_procedure(jp2->m_procedure_list,(void*)jp2_write_jp2c ); + /* DEVELOPER CORNER, add your custom procedures */ +} + /** * Sets up the procedures to do on reading header after the codestream. - * Developpers wanting to extend the library can add their own writting procedures. + * Developers wanting to extend the library can add their own writing procedures. */ void jp2_setup_end_header_reading (opj_jp2_v2_t *jp2) { @@ -1992,6 +2075,68 @@ void jp2_setup_end_header_reading (opj_jp2_v2_t *jp2) /* DEVELOPER CORNER, add your custom procedures */ } +/** + * 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. + */ +opj_bool jp2_default_validation ( opj_jp2_v2_t * jp2, + opj_stream_private_t *cio, + opj_event_mgr_t * p_manager ) +{ + opj_bool l_is_valid = OPJ_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; +} /** * Reads a jpeg2000 file header structure. @@ -2126,6 +2271,42 @@ opj_bool jp2_exec ( return l_result; } +/** + * 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. + */ +opj_bool jp2_start_compress(opj_jp2_v2_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 OPJ_FALSE; + } + + /* customization of the encoding */ + jp2_setup_header_writting(jp2); + + /* write header */ + if (! jp2_exec (jp2,jp2->m_procedure_list,cio,p_manager)) { + return OPJ_FALSE; + } + + return j2k_start_compress(jp2->j2k,cio,p_image,p_manager); +} /** * Finds the execution function related to the given box id. @@ -2288,6 +2469,32 @@ opj_bool jp2_read_ftyp_v2( return OPJ_TRUE; } +/** + * 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. +*/ +opj_bool jp2_skip_jp2c( opj_jp2_v2_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 OPJ_FALSE; + } + + return OPJ_TRUE; +} /** * Reads the Jpeg2000 file Header box - JP2 Header box (warning, this is a super box). @@ -2479,6 +2686,19 @@ opj_bool jp2_read_header( struct opj_stream_private *p_stream, p_manager); } +/** + * Sets up the validation ,i.e. adds the procedures to launch to make sure the codec parameters + * are valid. Developers wanting to extend the library can add their own validation procedures. + */ +void jp2_setup_encoding_validation (opj_jp2_v2_t *jp2) +{ + /* preconditions */ + assert(jp2 != 00); + + opj_procedure_list_add_procedure(jp2->m_validation_list, (void*)jp2_default_validation); + /* DEVELOPER CORNER, add your custom validation procedure */ +} + /** * 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. @@ -2490,6 +2710,24 @@ void jp2_setup_decoding_validation (opj_jp2_v2_t *jp2) /* DEVELOPER CORNER, add your custom validation procedure */ } +/** + * Sets up the procedures to do on writting header. + * Developers wanting to extend the library can add their own writing procedures. + */ +void jp2_setup_header_writting (opj_jp2_v2_t *jp2) +{ + /* preconditions */ + assert(jp2 != 00); + + opj_procedure_list_add_procedure(jp2->m_procedure_list,(void*)jp2_write_jp ); + opj_procedure_list_add_procedure(jp2->m_procedure_list,(void*)jp2_write_ftyp ); + opj_procedure_list_add_procedure(jp2->m_procedure_list,(void*)jp2_write_jp2h ); + opj_procedure_list_add_procedure(jp2->m_procedure_list,(void*)jp2_skip_jp2c ); + + /* DEVELOPER CORNER, insert your custom procedures */ + +} + /** * Sets up the procedures to do on reading header. * Developpers wanting to extend the library can add their own writting procedures. @@ -2531,6 +2769,22 @@ opj_bool jp2_read_tile_header( opj_jp2_v2_t * p_jp2, 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. + */ +opj_bool jp2_write_tile ( opj_jp2_v2_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. diff --git a/libopenjpeg/jp2.h b/libopenjpeg/jp2.h index d00b8d67..299215e0 100644 --- a/libopenjpeg/jp2.h +++ b/libopenjpeg/jp2.h @@ -330,6 +330,28 @@ Encode an image into a JPEG-2000 file stream opj_bool opj_jp2_encode(opj_jp2_t *jp2, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info); +/** + * 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. + */ +opj_bool jp2_start_compress(opj_jp2_v2_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. + */ +opj_bool jp2_end_compress( opj_jp2_v2_t *jp2, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager); + /* ----------------------------------------------------------------------- */ /** @@ -373,6 +395,21 @@ opj_bool jp2_read_tile_header ( 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. + */ +opj_bool jp2_write_tile ( opj_jp2_v2_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. diff --git a/libopenjpeg/mct.c b/libopenjpeg/mct.c index c29218a4..2cf581be 100644 --- a/libopenjpeg/mct.c +++ b/libopenjpeg/mct.c @@ -45,6 +45,16 @@ static const double mct_norms[3] = { 1.732, .8292, .8292 }; /* */ static const double 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; +} + /* */ /* Foward reversible MCT. */ /* */ @@ -190,6 +200,62 @@ double mct_getnorm_real(int compno) { } +opj_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 OPJ_FALSE; + } + + lCurrentMatrix = lCurrentData + pNbComp; + + for (i =0;iis_decompressor = 0; + + switch(p_format) { + case CODEC_J2K: + l_info->m_codec_data.m_compression.opj_encode = (opj_bool (*) ( void *, + struct opj_stream_private *, + struct opj_event_mgr * )) j2k_encode_v2; + + l_info->m_codec_data.m_compression.opj_end_compress = (opj_bool (*) ( void *, + struct opj_stream_private *, + struct opj_event_mgr *)) j2k_end_compress; + + l_info->m_codec_data.m_compression.opj_start_compress = (opj_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 = (opj_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_v2(); + if (! l_info->m_codec) { + opj_free(l_info); + return 00; + } + + break; + + case CODEC_JP2: + /* get a JP2 decoder handle */ + l_info->m_codec_data.m_compression.opj_encode = (opj_bool (*) ( void *, + struct opj_stream_private *, + struct opj_event_mgr * )) opj_jp2_encode; + + l_info->m_codec_data.m_compression.opj_end_compress = (opj_bool (*) ( void *, + struct opj_stream_private *, + struct opj_event_mgr *)) jp2_end_compress; + + l_info->m_codec_data.m_compression.opj_start_compress = (opj_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 = (opj_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(OPJ_FALSE); + if (! l_info->m_codec) { + opj_free(l_info); + return 00; + } + + break; + + case CODEC_UNKNOWN: + case CODEC_JPT: + default: + 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_destroy_compress(opj_cinfo_t *cinfo) { if(cinfo) { /* destroy the codec */ @@ -658,6 +777,66 @@ void OPJ_CALLCONV opj_setup_encoder(opj_cinfo_t *cinfo, opj_cparameters_t *param } } +opj_bool OPJ_CALLCONV opj_setup_encoder_v2(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 OPJ_TRUE; + } + } + + return OPJ_FALSE; +} + +opj_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 OPJ_FALSE; +} + +opj_bool OPJ_CALLCONV opj_encode_v2(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 OPJ_TRUE; + } + } + + return OPJ_FALSE; + +} + +opj_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 OPJ_FALSE; + +} + opj_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" @@ -1034,3 +1213,31 @@ opj_bool OPJ_CALLCONV opj_set_decoded_resolution_factor(opj_codec_t *p_codec, OP return OPJ_TRUE; } + + +opj_bool OPJ_CALLCONV 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 */ + int rsiz = (int)parameters->cp_rsiz | (int)MCT; + parameters->cp_rsiz = (OPJ_RSIZ_CAPABILITIES)rsiz; + 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 OPJ_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 OPJ_TRUE; +} + + + diff --git a/libopenjpeg/openjpeg.h b/libopenjpeg/openjpeg.h index b5772263..909dbf47 100644 --- a/libopenjpeg/openjpeg.h +++ b/libopenjpeg/openjpeg.h @@ -173,7 +173,8 @@ typedef OPJ_INT64 OPJ_OFF_T; 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; /** @@ -425,6 +426,9 @@ typedef struct opj_cparameters { char tcp_mct; /** Enable JPIP indexing*/ opj_bool jpip_on; + /** Naive implementation of MCT restricted to a single reversible array based encoding without offset concerning all the components. */ + void * mct_data; + } opj_cparameters_t; #define OPJ_DPARAMETERS_IGNORE_PCLR_CMAP_CDEF_FLAG 0x0001 @@ -1399,6 +1403,15 @@ Creates a J2K/JP2 compression structure @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); + +/** +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_codec_t* OPJ_CALLCONV opj_create_compress_v2(OPJ_CODEC_FORMAT format); + + /** Destroy a compressor handle @param cinfo compressor handle to destroy @@ -1433,6 +1446,32 @@ Setup the encoder parameters using the current image and using user 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); + +/** +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 opj_bool OPJ_CALLCONV opj_setup_encoder_v2(opj_codec_t *cinfo, opj_cparameters_t *parameters, opj_image_t *image); + + +opj_bool OPJ_CALLCONV opj_start_compress ( opj_codec_t *p_codec, + opj_image_t * p_image, + opj_stream_t *p_cio); + +opj_bool OPJ_CALLCONV opj_end_compress (opj_codec_t *p_codec,opj_stream_t *p_cio); + +/** +Encode an image into a JPEG-2000 codestream +@param cinfo compressor handle +@param cio Output buffer stream +@param image Image to encode +@param index Depreacted -> Set to NULL. To extract index, used opj_encode_wci() +@return Returns true if successful, returns false otherwise +*/ +OPJ_API opj_bool OPJ_CALLCONV opj_encode_v2(opj_codec_t *cinfo, opj_stream_t * cio); + /** Encode an image into a JPEG-2000 codestream 3@param cinfo compressor handle @@ -1537,6 +1576,26 @@ OPJ_API opj_jp2_metadata_t* OPJ_CALLCONV opj_get_jp2_metadata(opj_codec_t *p_cod OPJ_API opj_jp2_index_t* OPJ_CALLCONV opj_get_jp2_index(opj_codec_t *p_codec); +/* +========================================================== + new functions +========================================================== +*/ + +/** + * 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 opj_bool OPJ_CALLCONV opj_set_MCT( opj_cparameters_t *parameters, + OPJ_FLOAT32 * pEncodingMatrix, + OPJ_INT32 * p_dc_shift, + OPJ_UINT32 pNbComp); diff --git a/libopenjpeg/pi.c b/libopenjpeg/pi.c index 2d3354f2..06250321 100644 --- a/libopenjpeg/pi.c +++ b/libopenjpeg/pi.c @@ -69,7 +69,83 @@ Get next packet in component-precinct-resolution-layer order. */ static opj_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_v2_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_v2_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_v2_t *p_cp, + OPJ_UINT32 tileno, + OPJ_INT32 * p_tx0, + OPJ_INT32 * p_tx1, + OPJ_INT32 * p_ty0, + OPJ_INT32 * p_ty1, + OPJ_UINT32 * p_dx_min, + OPJ_UINT32 * p_dy_min, + OPJ_UINT32 * p_max_prec, + OPJ_UINT32 * p_max_res ); /** * Gets the encoding parameters needed to update the coding parameters and all the pocs. @@ -123,6 +199,12 @@ void pi_update_decode_not_poc (opj_pi_iterator_t * p_pi,opj_tcp_v2_t * p_tcp,OPJ void pi_update_decode_poc (opj_pi_iterator_t * p_pi,opj_tcp_v2_t * p_tcp,OPJ_UINT32 p_max_precision,OPJ_UINT32 p_max_res); +OPJ_INT32 pi_check_next_level( OPJ_INT32 pos, + opj_cp_v2_t *cp, + OPJ_UINT32 tileno, + OPJ_UINT32 pino, + const OPJ_CHAR *prog); + /*@}*/ /*@}*/ @@ -938,6 +1020,202 @@ opj_pi_iterator_t *pi_initialise_encode(opj_image_t *image, opj_cp_t *cp, int ti return 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_v2( + const opj_image_t *p_image, + opj_cp_v2_t *p_cp, + OPJ_UINT32 p_tile_no, + J2K_T2_MODE p_t2_mode + ) +{ + // 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; + + // pointers + opj_pi_iterator_t *l_pi = 00; + opj_tcp_v2_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); + + // initializations + l_tcp = &p_cp->tcps[p_tile_no]; + l_bound = l_tcp->numpocs+1; + + l_data_stride = 4 * J2K_MAXRLVLS; + l_tmp_data = (OPJ_UINT32*)opj_malloc( + l_data_stride * p_image->numcomps * sizeof(OPJ_UINT32)); + if (! l_tmp_data) { + return 00; + } + + l_tmp_ptr = (OPJ_UINT32**)opj_malloc( + p_image->numcomps * sizeof(OPJ_UINT32 *)); + if (! l_tmp_ptr) { + opj_free(l_tmp_data); + return 00; + } + + // memory allocation for pi + l_pi = pi_create(p_image,p_cp,p_tile_no); + if (!l_pi) { + opj_free(l_tmp_data); + opj_free(l_tmp_ptr); + return 00; + } + + l_encoding_value_ptr = l_tmp_data; + // update pointer array + for (compno = 0; compno < p_image->numcomps; ++compno) { + l_tmp_ptr[compno] = l_encoding_value_ptr; + l_encoding_value_ptr += l_data_stride; + } + + // get encoding parameters + get_all_encoding_parameters(p_image,p_cp,p_tile_no,&l_tx0,&l_tx1,&l_ty0,&l_ty1,&l_dx_min,&l_dy_min,&l_max_prec,&l_max_res,l_tmp_ptr); + + // step calculations + l_step_p = 1; + l_step_c = l_max_prec * l_step_p; + l_step_r = p_image->numcomps * l_step_c; + l_step_l = l_max_res * l_step_r; + + // set values for first packet iterator + l_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_v2(l_pi, l_bound); + return 00; + } + memset(l_current_pi->include,0,l_tcp->numlayers * l_step_l* sizeof(OPJ_INT16)); + + // special treatment for the first packet iterator + l_current_comp = l_current_pi->comps; + l_img_comp = p_image->comps; + l_tccp = l_tcp->tccps; + l_current_pi->tx0 = l_tx0; + l_current_pi->ty0 = l_ty0; + l_current_pi->tx1 = l_tx1; + l_current_pi->ty1 = l_ty1; + l_current_pi->dx = l_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; + } + ++l_current_pi; + + for (pino = 1 ; pinocomps; + opj_image_comp_t * l_img_comp = p_image->comps; + l_tccp = l_tcp->tccps; + + l_current_pi->tx0 = l_tx0; + l_current_pi->ty0 = l_ty0; + l_current_pi->tx1 = l_tx1; + l_current_pi->ty1 = l_ty1; + l_current_pi->dx = l_dx_min; + l_current_pi->dy = l_dy_min; + l_current_pi->step_p = l_step_p; + l_current_pi->step_c = l_step_c; + l_current_pi->step_r = l_step_r; + l_current_pi->step_l = l_step_l; + + /* allocation for components and number of components has already been calculated by pi_create */ + for (compno = 0; compno < l_current_pi->numcomps; ++compno) { + opj_pi_resolution_t *l_res = l_current_comp->resolutions; + l_encoding_value_ptr = l_tmp_ptr[compno]; + + l_current_comp->dx = l_img_comp->dx; + l_current_comp->dy = l_img_comp->dy; + /* resolutions have already been initialized */ + for (resno = 0; resno < l_current_comp->numresolutions; resno++) { + l_res->pdx = *(l_encoding_value_ptr++); + l_res->pdy = *(l_encoding_value_ptr++); + l_res->pw = *(l_encoding_value_ptr++); + l_res->ph = *(l_encoding_value_ptr++); + ++l_res; + } + ++l_current_comp; + ++l_img_comp; + ++l_tccp; + } + + // special treatment + l_current_pi->include = (l_current_pi-1)->include; + ++l_current_pi; + } + + opj_free(l_tmp_data); + l_tmp_data = 00; + opj_free(l_tmp_ptr); + l_tmp_ptr = 00; + + if (l_tcp->POC && ( 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; +} void pi_destroy(opj_pi_iterator_t *pi, opj_cp_t *cp, int tileno) { @@ -1216,7 +1494,172 @@ opj_bool pi_create_encode( opj_pi_iterator_t *pi, opj_cp_t *cp,int tileno, int p return OPJ_FALSE; } +/** + * 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_v2_t *p_cp, + OPJ_UINT32 p_tile_no ) +{ + /* encoding parameters 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_v2_t *l_tcp = 00; + + /* preconditions */ + 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_v2_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_v2_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 */ + 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) { + /* arithmetic 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. @@ -1435,7 +1878,164 @@ opj_pi_iterator_t * pi_create( const opj_image_t *image, 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_v2_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_v2_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_v2_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_v2_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; + + 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. @@ -1561,3 +2161,354 @@ void pi_update_decode_not_poc (opj_pi_iterator_t * p_pi,opj_tcp_v2_t * p_tcp,OPJ ++l_current_pi; } } + + +void pi_create_encode_v2( opj_pi_iterator_t *pi, + opj_cp_v2_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_v2_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; + pi[pino].poc.compno1 = tcp->compE; + pi[pino].poc.layno0 = tcp->layS; + pi[pino].poc.layno1 = tcp->layE; + pi[pino].poc.precno0 = tcp->prcS; + pi[pino].poc.precno1 = tcp->prcE; + 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 { + 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': + tcp->comp_t = tcp->compS; + pi[pino].poc.compno0 = tcp->comp_t; + pi[pino].poc.compno1 = tcp->comp_t+1; + tcp->comp_t+=1; + 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; + 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){ + 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; + } + 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){ + 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; + } + break; + case 'P': + switch(tcp->prg){ + case LRCP: + case RLCP: + if(tcp->prc_t == tcp->prcE){ + 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; + } + break; + default: + if(tcp->tx0_t >= tcp->txE){ + if(tcp->ty0_t >= tcp->tyE){ + 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); + tcp->ty0_t = pi[pino].poc.ty1; + incr_top=0;resetX=1; + } + if(resetX==1){ + tcp->tx0_t = tcp->txS; + 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; + } + }else{ + 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; + incr_top=0; + } + break; + } + break; + } + } + } + } + } +} + +OPJ_INT32 pi_check_next_level( OPJ_INT32 pos, + opj_cp_v2_t *cp, + OPJ_UINT32 tileno, + OPJ_UINT32 pino, + const OPJ_CHAR *prog) +{ + OPJ_INT32 i,l; + opj_tcp_v2_t *tcps =&cp->tcps[tileno]; + 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 '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 '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 '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; +} diff --git a/libopenjpeg/pi.h b/libopenjpeg/pi.h index 5c7b9981..d1c8abf5 100644 --- a/libopenjpeg/pi.h +++ b/libopenjpeg/pi.h @@ -110,6 +110,33 @@ Create a packet iterator for Encoder @see pi_destroy */ opj_pi_iterator_t *pi_initialise_encode(opj_image_t *image, opj_cp_t *cp, int tileno,J2K_T2_MODE t2_mode); + +/** + * 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_v2( const struct opj_image *image, + struct opj_cp_v2 *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_v2 *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 @@ -123,6 +150,19 @@ Modify the packet iterator for enabling tile part generation @return Returns true if an error is detected */ opj_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); + +/** +Modify the packet iterator for enabling tile part generation +@param pi Handle to the packet iterator generated in pi_initialise_encode +@param cp Coding parameters +@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 +*/ +void pi_create_encode_v2( opj_pi_iterator_t *pi, struct opj_cp_v2 *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 diff --git a/libopenjpeg/t1.c b/libopenjpeg/t1.c index 32257912..5ace77be 100644 --- a/libopenjpeg/t1.c +++ b/libopenjpeg/t1.c @@ -274,6 +274,17 @@ static double t1_getwmsedec( double stepsize, int numcomps, int mct); + +static OPJ_FLOAT64 t1_getwmsedec_v2( + 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 @@ -300,6 +311,20 @@ static void t1_encode_cblk( int numcomps, int mct, opj_tcd_tile_t * tile); + +static void t1_encode_cblk_v2( + opj_t1_t *t1, + opj_tcd_cblk_enc_v2_t* cblk, + OPJ_UINT32 orient, + OPJ_UINT32 compno, + OPJ_UINT32 level, + OPJ_UINT32 qmfbid, + OPJ_FLOAT64 stepsize, + OPJ_UINT32 cblksty, + OPJ_UINT32 numcomps, + opj_tcd_tile_v2_t * tile, + const OPJ_FLOAT64 * mct_norms); + /** Decode 1 code-block @param t1 T1 handle @@ -1165,6 +1190,36 @@ static double t1_getwmsedec( return wmsedec; } +/** mod fixed_quality */ +static OPJ_FLOAT64 t1_getwmsedec_v2( + 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) +{ + 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) */ + w2 = dwt_getnorm_real(level, orient); + } + + wmsedec = w1 * w2 * stepsize * (1 << bpno); + wmsedec *= wmsedec * nmsedec / 8192.0; + + return wmsedec; +} + static opj_bool allocate_buffers( opj_t1_t *t1, int w, @@ -1655,28 +1710,24 @@ opj_t1_t* t1_create_v2() opj_t1_t *l_t1 = 00; l_t1 = (opj_t1_t*) opj_malloc(sizeof(opj_t1_t)); - if - (!l_t1) - { + if (!l_t1) { return 00; } memset(l_t1,0,sizeof(opj_t1_t)); /* create MQC and RAW handles */ l_t1->mqc = mqc_create(); - if - (! l_t1->mqc) - { + if (! l_t1->mqc) { t1_destroy(l_t1); return 00; } + l_t1->raw = raw_create(); - if - (! l_t1->raw) - { + if (! l_t1->raw) { t1_destroy(l_t1); return 00; } + return l_t1; } @@ -1873,6 +1924,241 @@ static void t1_decode_cblk_v2( } } +opj_bool t1_encode_cblks_v2( + opj_t1_t *t1, + opj_tcd_tile_v2_t *tile, + opj_tcp_v2_t *tcp, + const OPJ_FLOAT64 * mct_norms) +{ + OPJ_UINT32 compno, resno, bandno, precno, cblkno; + + tile->distotile = 0; /* fixed_quality */ + + for (compno = 0; compno < tile->numcomps; ++compno) { + opj_tcd_tilecomp_v2_t* tilec = &tile->comps[compno]; + opj_tccp_t* tccp = &tcp->tccps[compno]; + OPJ_UINT32 tile_w = tilec->x1 - tilec->x0; + + for (resno = 0; resno < tilec->numresolutions; ++resno) { + opj_tcd_resolution_v2_t *res = &tilec->resolutions[resno]; + + for (bandno = 0; bandno < res->numbands; ++bandno) { + opj_tcd_band_v2_t* restrict band = &res->bands[bandno]; + + for (precno = 0; precno < res->pw * res->ph; ++precno) { + opj_tcd_precinct_v2_t *prc = &band->precincts[precno]; + + for (cblkno = 0; cblkno < prc->cw * prc->ch; ++cblkno) { + opj_tcd_cblk_enc_v2_t* cblk = &prc->cblks.enc[cblkno]; + 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_v2_t *pres = &tilec->resolutions[resno - 1]; + x += pres->x1 - pres->x0; + } + if (band->bandno & 2) { + opj_tcd_resolution_v2_t *pres = &tilec->resolutions[resno - 1]; + y += pres->y1 - pres->y0; + } + + if(!allocate_buffers( + t1, + cblk->x1 - cblk->x0, + cblk->y1 - cblk->y0)) + { + return OPJ_FALSE; + } + + datap=t1->data; + cblk_w = t1->w; + cblk_h = t1->h; + + tiledp=&tilec->data[(y * tile_w) + x]; + if (tccp->qmfbid == 1) { + for (j = 0; j < cblk_h; ++j) { + for (i = 0; i < cblk_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) { + OPJ_INT32 tmp = tiledp[(j * tile_w) + i]; + datap[(j * cblk_w) + i] = + fix_mul( + tmp, + 8192 * 8192 / ((OPJ_INT32) floor(band->stepsize * 8192))) >> (11 - T1_NMSEDEC_FRACBITS); + } + } + } + + t1_encode_cblk_v2( + t1, + cblk, + band->bandno, + compno, + tilec->numresolutions - 1 - resno, + tccp->qmfbid, + band->stepsize, + tccp->cblksty, + tile->numcomps, + tile, + mct_norms); + + } /* cblkno */ + } /* precno */ + } /* bandno */ + } /* resno */ + } /* compno */ + return OPJ_TRUE; +} + +/** mod fixed_quality */ +static void t1_encode_cblk_v2( + opj_t1_t *t1, + opj_tcd_cblk_enc_v2_t* cblk, + OPJ_UINT32 orient, + OPJ_UINT32 compno, + OPJ_UINT32 level, + OPJ_UINT32 qmfbid, + OPJ_FLOAT64 stepsize, + OPJ_UINT32 cblksty, + OPJ_UINT32 numcomps, + opj_tcd_tile_v2_t * tile, + const OPJ_FLOAT64 * mct_norms) +{ + OPJ_FLOAT64 cumwmsedec = 0.0; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + 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) { + OPJ_INT32 tmp = abs(t1->data[i]); + max = int_max(max, tmp); + } + + cblk->numbps = max ? (int_floorlog2(max) + 1) - T1_NMSEDEC_FRACBITS : 0; + + bpno = cblk->numbps - 1; + passtype = 2; + + mqc_resetstates(mqc); + mqc_setstate(mqc, T1_CTXNO_UNI, 0, 46); + mqc_setstate(mqc, T1_CTXNO_AGG, 0, 3); + mqc_setstate(mqc, T1_CTXNO_ZC, 0, 4); + mqc_init_enc(mqc, cblk->data); + + for (passno = 0; bpno >= 0; ++passno) { + opj_tcd_pass_v2_t *pass = &cblk->passes[passno]; + 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: + t1_enc_sigpass(t1, bpno, orient, &nmsedec, type, cblksty); + break; + case 1: + t1_enc_refpass(t1, bpno, &nmsedec, type, cblksty); + break; + case 2: + t1_enc_clnpass(t1, bpno, orient, &nmsedec, cblksty); + /* code switch SEGMARK (i.e. SEGSYM) */ + if (cblksty & J2K_CCP_CBLKSTY_SEGSYM) + mqc_segmark_enc(mqc); + break; + } + + /* fixed_quality */ + tempwmsedec = t1_getwmsedec_v2(nmsedec, compno, level, orient, bpno, qmfbid, stepsize, numcomps,mct_norms) ; + cumwmsedec += tempwmsedec; + tile->distotile += tempwmsedec; + + /* Code switch "RESTART" (i.e. TERMALL) */ + if ((cblksty & J2K_CCP_CBLKSTY_TERMALL) && !((passtype == 2) && (bpno - 1 < 0))) { + if (type == T1_TYPE_RAW) { + mqc_flush(mqc); + correction = 1; + /* correction = mqc_bypass_flush_enc(); */ + } else { /* correction = mqc_restart_enc(); */ + mqc_flush(mqc); + correction = 1; + } + pass->term = 1; + } else { + 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); + correction = 1; + /* correction = mqc_bypass_flush_enc(); */ + } else { /* correction = mqc_restart_enc(); */ + mqc_flush(mqc); + correction = 1; + } + pass->term = 1; + } else { + pass->term = 0; + } + } + + if (++passtype == 3) { + passtype = 0; + bpno--; + } + + if (pass->term && bpno > 0) { + 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 + mqc_restart_init_enc(mqc); + } + + pass->distortiondec = cumwmsedec; + pass->rate = mqc_numbytes(mqc) + correction; /* FIXME */ + + /* Code-switch "RESET" */ + if (cblksty & J2K_CCP_CBLKSTY_RESET) + mqc_reset_enc(mqc); + } + + /* Code switch "ERTERM" (i.e. PTERM) */ + if (cblksty & J2K_CCP_CBLKSTY_PTERM) + mqc_erterm_enc(mqc); + else /* Default coding */ if (!(cblksty & J2K_CCP_CBLKSTY_LAZY)) + mqc_flush(mqc); + + cblk->totalpasses = passno; + + for (passno = 0; passnototalpasses; passno++) { + opj_tcd_pass_v2_t *pass = &cblk->passes[passno]; + if (pass->rate > mqc_numbytes(mqc)) + pass->rate = mqc_numbytes(mqc); + /*Preventing generation of FF as last data byte of a pass*/ + if((pass->rate>1) && (cblk->data[pass->rate - 1] == 0xFF)){ + pass->rate--; + } + pass->len = pass->rate - (passno == 0 ? 0 : cblk->passes[passno - 1].rate); + } +} + + static void t1_dec_refpass( opj_t1_t *t1, OPJ_INT32 bpno, diff --git a/libopenjpeg/t1.h b/libopenjpeg/t1.h index bebf47ca..ca74e955 100644 --- a/libopenjpeg/t1.h +++ b/libopenjpeg/t1.h @@ -132,6 +132,12 @@ Encode the code-blocks of a tile @param tcp Tile coding parameters */ void t1_encode_cblks(opj_t1_t *t1, opj_tcd_tile_t *tile, opj_tcp_t *tcp); + +opj_bool t1_encode_cblks_v2(opj_t1_t *t1, + struct opj_tcd_tile_v2 *tile, + struct opj_tcp_v2 *tcp, + const OPJ_FLOAT64 * mct_norms); + /** Decode the code-blocks of a tile @param t1 T1 handle diff --git a/libopenjpeg/t2.c b/libopenjpeg/t2.c index 63e6e3a8..a091ef22 100644 --- a/libopenjpeg/t2.c +++ b/libopenjpeg/t2.c @@ -58,6 +58,28 @@ Encode a packet of a tile to a destination buffer @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); + +/** +Encode a packet of a tile to a destination buffer +@param tile Tile for which to write the packets +@param tcp Tile coding parameters +@param pi Packet identity +@param dest Destination buffer +@param len Length of the destination buffer +@param cstr_info Codestream information structure +@param tileno Number of the tile encoded +@return +*/ +static opj_bool t2_encode_packet_v2( + OPJ_UINT32 tileno, + opj_tcd_tile_v2_t *tile, + opj_tcp_v2_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 cblk @param index @@ -754,6 +776,128 @@ int t2_encode_packets(opj_t2_t* t2,int tileno, opj_tcd_tile_t *tile, int maxlaye return (c - dest); } +opj_bool t2_encode_packets_v2( + opj_t2_v2_t* p_t2, + OPJ_UINT32 p_tile_no, + opj_tcd_tile_v2_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_v2_t *l_cp = p_t2->cp; + opj_tcp_v2_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_v2(l_image, l_cp, p_tile_no, p_t2_mode); + if (!l_pi) { + return OPJ_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_v2(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_v2(p_tile_no,p_tile, l_tcp, l_current_pi, l_current_data, &l_nb_bytes, p_max_len, cstr_info)) { + pi_destroy_v2(l_pi, l_nb_pocs); + return OPJ_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 (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_v2(l_pi, l_nb_pocs); + return OPJ_FALSE; + } + } + + ++l_current_pi; + } + } + } + else { /* t2_mode == FINAL_PASS */ + pi_create_encode_v2(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_v2(p_tile_no,p_tile, l_tcp, l_current_pi, l_current_data, &l_nb_bytes, p_max_len, cstr_info)) { + pi_destroy_v2(l_pi, l_nb_pocs); + return OPJ_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[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 = ((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 + 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 + } + + cstr_info->packno++; + } + /* << INDEX */ + ++p_tile->packno; + } + } + } + + pi_destroy_v2(l_pi, l_nb_pocs); + + return OPJ_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; @@ -1052,6 +1196,232 @@ static opj_bool t2_decode_packet_v2( return OPJ_TRUE; } +static opj_bool t2_encode_packet_v2( + OPJ_UINT32 tileno, + opj_tcd_tile_v2_t * tile, + opj_tcp_v2_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_v2_t *band = 00; + opj_tcd_cblk_enc_v2_t* cblk = 00; + opj_tcd_pass_v2_t *pass = 00; + + opj_tcd_tilecomp_v2_t *tilec = &tile->comps[compno]; + opj_tcd_resolution_v2_t *res = &tilec->resolutions[resno]; + + opj_bio_t *bio = 00; /* BIO component */ + + /* */ + if (tcp->csty & J2K_CP_CSTY_SOP) { + c[0] = 255; + c[1] = 145; + c[2] = 0; + c[3] = 4; + c[4] = (tile->packno % 65536) / 256; + c[5] = (tile->packno % 65536) % 256; + c += 6; + length -= 6; + } + /* */ + + if (!layno) { + band = res->bands; + + for(bandno = 0; bandno < res->numbands; ++bandno) { + opj_tcd_precinct_v2_t *prc = &band->precincts[precno]; + + tgt_reset(prc->incltree); + tgt_reset(prc->imsbtree); + + l_nb_blocks = prc->cw * prc->ch; + for (cblkno = 0; cblkno < l_nb_blocks; ++cblkno) { + opj_tcd_cblk_enc_v2_t* cblk = &prc->cblks.enc[cblkno]; + + cblk->numpasses = 0; + tgt_setvalue(prc->imsbtree, cblkno, band->numbps - cblk->numbps); + } + ++band; + } + } + + bio = bio_create(); + bio_init_enc(bio, c, length); + bio_write(bio, 1, 1); /* Empty header bit */ + + /* Writing Packet header */ + band = res->bands; + for (bandno = 0; bandno < res->numbands; ++bandno) { + opj_tcd_precinct_v2_t *prc = &band->precincts[precno]; + + 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) { + tgt_setvalue(prc->incltree, cblkno, layno); + } + + ++cblk; + } + + cblk = prc->cblks.enc; + for (cblkno = 0; cblkno < l_nb_blocks; cblkno++) { + opj_tcd_layer_t *layer = &cblk->layers[layno]; + 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); + } else { + bio_write(bio, layer->numpasses != 0, 1); + } + + /* if cblk not included, go to the next cblk */ + if (!layer->numpasses) { + ++cblk; + continue; + } + + /* if first instance of cblk --> zero bit-planes information */ + 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 < l_nb_passes; ++passno) { + ++nump; + len += pass->len; + + 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 < l_nb_passes; ++passno) { + nump++; + len += pass->len; + + 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)) { + bio_destroy(bio); + return OPJ_FALSE; /* modified to eliminate longjmp !! */ + } + + l_nb_bytes = bio_numbytes(bio); + c += l_nb_bytes; + length -= l_nb_bytes; + + bio_destroy(bio); + + /* */ + if (tcp->csty & J2K_CP_CSTY_EPH) { + c[0] = 255; + c[1] = 146; + c += 2; + length -= 2; + } + /* */ + + /* << 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(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 = (OPJ_INT32)(c - dest); + } + /* INDEX >> */ + + /* Writing the packet body */ + band = res->bands; + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_precinct_v2_t *prc = &band->precincts[precno]; + + 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) { + ++cblk; + continue; + } + + if (layer->len > length) { + return OPJ_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]; + info_PK->disto += layer->disto; + if (cstr_info->D_max < info_PK->disto) { + cstr_info->D_max = info_PK->disto; + } + } + + ++cblk; + /* INDEX >> */ + } + ++band; + } + + * p_data_written += (c - dest); + + return OPJ_TRUE; +} + static opj_bool t2_skip_packet( opj_t2_v2_t* p_t2, opj_tcd_tile_v2_t *p_tile, diff --git a/libopenjpeg/t2.h b/libopenjpeg/t2.h index f1637fba..2273c44e 100644 --- a/libopenjpeg/t2.h +++ b/libopenjpeg/t2.h @@ -85,6 +85,33 @@ Encode the packets of a tile to a destination buffer @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); + +/** +Encode the packets of a tile to a destination buffer +@param t2 T2 handle +@param tileno number of the tile encoded +@param tile the tile for which to write the packets +@param maxlayers maximum number of layers +@param dest the destination buffer +@param len the length of the destination buffer +@param cstr_info Codestream information structure +@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 +*/ +opj_bool t2_encode_packets_v2( opj_t2_v2_t* t2, + OPJ_UINT32 tileno, + struct opj_tcd_tile_v2 *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 diff --git a/libopenjpeg/tcd.c b/libopenjpeg/tcd.c index ea09a17f..3b866dd1 100644 --- a/libopenjpeg/tcd.c +++ b/libopenjpeg/tcd.c @@ -32,6 +32,30 @@ #include "opj_includes.h" +/* ----------------------------------------------------------------------- */ + +static opj_bool tcd_dc_level_shift_encode ( opj_tcd_v2_t *p_tcd ); + +static opj_bool tcd_mct_encode ( opj_tcd_v2_t *p_tcd ); + +static opj_bool tcd_dwt_encode ( opj_tcd_v2_t *p_tcd ); + +static opj_bool tcd_t1_encode ( opj_tcd_v2_t *p_tcd ); + +static opj_bool tcd_t2_encode ( opj_tcd_v2_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 ); + +static opj_bool tcd_rate_allocate_encode( opj_tcd_v2_t *p_tcd, + OPJ_BYTE * p_dest_data, + OPJ_UINT32 p_max_dest_size, + opj_codestream_info_t *p_cstr_info ); + +/* ----------------------------------------------------------------------- */ + + void tcd_dump(FILE *fd, opj_tcd_t *tcd, opj_tcd_image_t * img) { int tileno, compno, resno, bandno, precno;/*, cblkno;*/ @@ -95,6 +119,12 @@ void tcd_dump(FILE *fd, opj_tcd_t *tcd, opj_tcd_image_t * img) { */ static opj_bool tcd_code_block_dec_allocate (opj_tcd_cblk_dec_v2_t * p_code_block); +/** + * Allocates memory for an encoding code block. + */ +static opj_bool tcd_code_block_enc_allocate (opj_tcd_cblk_enc_v2_t * p_code_block); + + /** Free the memory allocated for encoding @param tcd TCD handle @@ -992,6 +1022,14 @@ void tcd_rateallocate_fixed(opj_tcd_t *tcd) { } } +void tcd_rateallocate_fixed_v2(opj_tcd_v2_t *tcd) { + OPJ_UINT32 layno; + + for (layno = 0; layno < tcd->tcp->numlayers; layno++) { + tcd_makelayer_fixed_v2(tcd, layno, 1); + } +} + void tcd_makelayer(opj_tcd_t *tcd, int layno, double thresh, int final) { int compno, resno, bandno, precno, cblkno, passno; @@ -1062,6 +1100,184 @@ void tcd_makelayer(opj_tcd_t *tcd, int layno, double thresh, int final) { } } +void tcd_makelayer_v2( opj_tcd_v2_t *tcd, + OPJ_UINT32 layno, + OPJ_FLOAT64 thresh, + OPJ_UINT32 final) +{ + OPJ_UINT32 compno, resno, bandno, precno, cblkno; + OPJ_UINT32 passno; + + opj_tcd_tile_v2_t *tcd_tile = tcd->tcd_image->tiles; + + tcd_tile->distolayer[layno] = 0; /* fixed_quality */ + + for (compno = 0; compno < tcd_tile->numcomps; compno++) { + opj_tcd_tilecomp_v2_t *tilec = &tcd_tile->comps[compno]; + + for (resno = 0; resno < tilec->numresolutions; resno++) { + opj_tcd_resolution_v2_t *res = &tilec->resolutions[resno]; + + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_v2_t *band = &res->bands[bandno]; + + for (precno = 0; precno < res->pw * res->ph; precno++) { + opj_tcd_precinct_v2_t *prc = &band->precincts[precno]; + + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + opj_tcd_cblk_enc_v2_t *cblk = &prc->cblks.enc[cblkno]; + opj_tcd_layer_t *layer = &cblk->layers[layno]; + OPJ_UINT32 n; + + if (layno == 0) { + cblk->numpassesinlayers = 0; + } + + n = cblk->numpassesinlayers; + + for (passno = cblk->numpassesinlayers; passno < cblk->totalpasses; passno++) { + OPJ_INT32 dr; + OPJ_FLOAT64 dd; + opj_tcd_pass_v2_t *pass = &cblk->passes[passno]; + + if (n == 0) { + dr = pass->rate; + dd = pass->distortiondec; + } else { + dr = pass->rate - cblk->passes[n - 1].rate; + dd = pass->distortiondec - cblk->passes[n - 1].distortiondec; + } + + if (!dr) { + if (dd != 0) + n = passno + 1; + continue; + } + if (dd / dr >= thresh) + n = passno + 1; + } + + layer->numpasses = n - cblk->numpassesinlayers; + + if (!layer->numpasses) { + layer->disto = 0; + continue; + } + + if (cblk->numpassesinlayers == 0) { + layer->len = cblk->passes[n - 1].rate; + layer->data = cblk->data; + layer->disto = cblk->passes[n - 1].distortiondec; + } else { + layer->len = cblk->passes[n - 1].rate - cblk->passes[cblk->numpassesinlayers - 1].rate; + layer->data = cblk->data + cblk->passes[cblk->numpassesinlayers - 1].rate; + layer->disto = cblk->passes[n - 1].distortiondec - cblk->passes[cblk->numpassesinlayers - 1].distortiondec; + } + + tcd_tile->distolayer[layno] += layer->disto; /* fixed_quality */ + + if (final) + cblk->numpassesinlayers = n; + } + } + } + } + } +} + +void tcd_makelayer_fixed_v2(opj_tcd_v2_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_v2_t *cp = tcd->cp; + opj_tcd_tile_v2_t *tcd_tile = tcd->tcd_image->tiles; + opj_tcp_v2_t *tcd_tcp = tcd->tcp; + + for (compno = 0; compno < tcd_tile->numcomps; compno++) { + opj_tcd_tilecomp_v2_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] = + (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)); + } + } + } + + for (resno = 0; resno < tilec->numresolutions; resno++) { + opj_tcd_resolution_v2_t *res = &tilec->resolutions[resno]; + + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_v2_t *band = &res->bands[bandno]; + + for (precno = 0; precno < res->pw * res->ph; precno++) { + opj_tcd_precinct_v2_t *prc = &band->precincts[precno]; + + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + opj_tcd_cblk_enc_v2_t *cblk = &prc->cblks.enc[cblkno]; + opj_tcd_layer_t *layer = &cblk->layers[layno]; + 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]; + if (imsb >= value) { + value = 0; + } else { + value -= imsb; + } + } else { + value = matrice[layno][resno][bandno] - matrice[layno - 1][resno][bandno]; + if (imsb >= matrice[layno - 1][resno][bandno]) { + value -= (imsb - matrice[layno - 1][resno][bandno]); + if (value < 0) { + value = 0; + } + } + } + + if (layno == 0) { + cblk->numpassesinlayers = 0; + } + + n = cblk->numpassesinlayers; + if (cblk->numpassesinlayers == 0) { + if (value != 0) { + n = 3 * value - 2 + cblk->numpassesinlayers; + } else { + n = cblk->numpassesinlayers; + } + } else { + n = 3 * value + cblk->numpassesinlayers; + } + + layer->numpasses = n - cblk->numpassesinlayers; + + if (!layer->numpasses) + continue; + + if (cblk->numpassesinlayers == 0) { + layer->len = cblk->passes[n - 1].rate; + layer->data = cblk->data; + } else { + layer->len = cblk->passes[n - 1].rate - cblk->passes[cblk->numpassesinlayers - 1].rate; + layer->data = cblk->data + cblk->passes[cblk->numpassesinlayers - 1].rate; + } + + if (final) + cblk->numpassesinlayers = n; + } + } + } + } + } +} + opj_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; @@ -1229,97 +1445,286 @@ opj_bool tcd_rateallocate(opj_tcd_t *tcd, unsigned char *dest, int len, opj_code return OPJ_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_bool tcd_rateallocate_v2( opj_tcd_v2_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_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_cp_v2_t *cp = tcd->cp; + opj_tcd_tile_v2_t *tcd_tile = tcd->tcd_image->tiles; + opj_tcp_v2_t *tcd_tcp = tcd->tcp; - tcd->tcd_tileno = tileno; - tcd->tcd_tile = tcd->tcd_image->tiles; - tcd->tcp = &tcd->cp->tcps[tileno]; + min = DBL_MAX; + max = 0; - tile = tcd->tcd_tile; - tcd_tcp = tcd->tcp; - cp = tcd->cp; + tcd_tile->numpix = 0; /* fixed_quality */ - 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)); - } - /* << 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; - } - } - } 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; - } - - } - } - } - - /*----------------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); - } - } - + for (compno = 0; compno < tcd_tile->numcomps; compno++) { + opj_tcd_tilecomp_v2_t *tilec = &tcd_tile->comps[compno]; + tilec->numpix = 0; + + for (resno = 0; resno < tilec->numresolutions; resno++) { + opj_tcd_resolution_v2_t *res = &tilec->resolutions[resno]; + + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_v2_t *band = &res->bands[bandno]; + + for (precno = 0; precno < res->pw * res->ph; precno++) { + opj_tcd_precinct_v2_t *prc = &band->precincts[precno]; + + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + opj_tcd_cblk_enc_v2_t *cblk = &prc->cblks.enc[cblkno]; + + for (passno = 0; passno < cblk->totalpasses; passno++) { + opj_tcd_pass_v2_t *pass = &cblk->passes[passno]; + OPJ_INT32 dr; + OPJ_FLOAT64 dd, rdslope; + + if (passno == 0) { + dr = pass->rate; + dd = pass->distortiondec; + } else { + dr = pass->rate - cblk->passes[passno - 1].rate; + dd = pass->distortiondec - cblk->passes[passno - 1].distortiondec; + } + + if (dr == 0) { + continue; + } + + rdslope = dd / dr; + if (rdslope < min) { + min = rdslope; + } + + if (rdslope > max) { + max = rdslope; + } + } /* passno */ + + /* fixed_quality */ + tcd_tile->numpix += ((cblk->x1 - cblk->x0) * (cblk->y1 - cblk->y0)); + tilec->numpix += ((cblk->x1 - cblk->x0) * (cblk->y1 - cblk->y0)); + } /* cbklno */ + } /* precno */ + } /* bandno */ + } /* resno */ + + 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 */ + if(cstr_info) { + 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 = (OPJ_FLOAT64 *) opj_malloc(tcd_tcp->numlayers * sizeof(OPJ_FLOAT64)); + } + + for (layno = 0; layno < tcd_tcp->numlayers; layno++) { + OPJ_FLOAT64 lo = min; + OPJ_FLOAT64 hi = max; + opj_bool success = OPJ_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((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->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_v2_t*t2 = t2_create_v2(tcd->image, cp); + OPJ_FLOAT64 thresh = 0; + + if (t2 == 00) { + return OPJ_FALSE; + } + + for (i = 0; i < 128; ++i) { + OPJ_FLOAT64 distoachieved = 0; /* fixed_quality */ + + thresh = (lo + hi) / 2; + + tcd_makelayer_v2(tcd, layno, thresh, 0); + + 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_v2(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 { + distoachieved = layno == 0 ? + tcd_tile->distolayer[0] : cumdisto[layno - 1] + tcd_tile->distolayer[layno]; + + if (distoachieved < distotarget) { + hi=thresh; + stable_thresh = thresh; + continue; + }else{ + lo=thresh; + } + } + }else{ + distoachieved = (layno == 0) ? + tcd_tile->distolayer[0] : (cumdisto[layno - 1] + tcd_tile->distolayer[layno]); + + if (distoachieved < distotarget) { + hi = thresh; + stable_thresh = thresh; + continue; + } + lo = thresh; + } + } else { + if (! t2_encode_packets_v2(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; + } + + hi = thresh; + stable_thresh = thresh; + } + } + + success = OPJ_TRUE; + goodthresh = stable_thresh == 0? thresh : stable_thresh; + + t2_destroy_v2(t2); + } else { + success = OPJ_TRUE; + goodthresh = min; + } + + if (!success) { + return OPJ_FALSE; + } + + if(cstr_info) { /* Threshold for Marcela Index */ + cstr_info->tile[tcd->tcd_tileno].thresh[layno] = goodthresh; + } + + tcd_makelayer_v2(tcd, layno, goodthresh, 1); + + /* fixed_quality */ + cumdisto[layno] = (layno == 0) ? tcd_tile->distolayer[0] : (cumdisto[layno - 1] + tcd_tile->distolayer[layno]); + } + + return OPJ_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 */ + + tcd->tcd_tileno = tileno; + tcd->tcd_tile = tcd->tcd_image->tiles; + tcd->tcp = &tcd->cp->tcps[tileno]; + + tile = tcd->tcd_tile; + tcd_tcp = tcd->tcp; + cp = tcd->cp; + + 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)); + } + /* << 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; + } + } + } 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; + } + + } + } + } + + /*----------------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); + } + } + /*----------------DWT---------------------*/ for (compno = 0; compno < tile->numcomps; compno++) { @@ -1993,54 +2398,200 @@ opj_bool FUNCTION ( opj_tcd_v2_t *p_tcd, \ } \ -/* V2 ENCODE MACRO_TCD_ALLOCATE(tcd_init_encode_tile,opj_tcd_cblk_enc_t,1.f,enc,tcd_code_block_enc_allocate) */ +MACRO_TCD_ALLOCATE(tcd_init_encode_tile, opj_tcd_cblk_enc_v2_t, 1.f, enc, tcd_code_block_enc_allocate) MACRO_TCD_ALLOCATE(tcd_init_decode_tile, opj_tcd_cblk_dec_v2_t, 0.5f, dec, tcd_code_block_dec_allocate) #undef MACRO_TCD_ALLOCATE - -OPJ_UINT32 tcd_get_decoded_tile_size ( opj_tcd_v2_t *p_tcd ) +/** + * Allocates memory for an encoding code block. + */ +opj_bool tcd_code_block_enc_allocate (opj_tcd_cblk_enc_v2_t * p_code_block) { - OPJ_UINT32 i; - OPJ_UINT32 l_data_size = 0; - opj_image_comp_t * l_img_comp = 00; - opj_tcd_tilecomp_v2_t * l_tile_comp = 00; - opj_tcd_resolution_v2_t * l_res = 00; - OPJ_UINT32 l_size_comp, l_remaining; + if (! p_code_block->data) { - l_tile_comp = p_tcd->tcd_image->tiles->comps; - l_img_comp = p_tcd->image->comps; + p_code_block->data = (OPJ_BYTE*) opj_malloc(8192+1); + if(! p_code_block->data) { + return OPJ_FALSE; + } - for (i=0;iimage->numcomps;++i) { - l_size_comp = l_img_comp->prec >> 3; /*(/ 8)*/ - l_remaining = l_img_comp->prec & 7; /* (%8) */ + p_code_block->data+=1; - if(l_remaining) { - ++l_size_comp; + /* 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 OPJ_FALSE; } - if (l_size_comp == 3) { - l_size_comp = 4; + p_code_block->passes = (opj_tcd_pass_v2_t*) opj_malloc(100 * sizeof(opj_tcd_pass_v2_t)); + if (! p_code_block->passes) { + return OPJ_FALSE; } - - 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; -} + memset(p_code_block->layers,0,100 * sizeof(opj_tcd_layer_t)); + memset(p_code_block->passes,0,100 * sizeof(opj_tcd_pass_v2_t)); + return OPJ_TRUE; +} -opj_bool tcd_decode_tile_v2( - opj_tcd_v2_t *p_tcd, - OPJ_BYTE *p_src, - OPJ_UINT32 p_max_length, - OPJ_UINT32 p_tile_no, - opj_codestream_index_t *p_cstr_index) +/** + * Allocates memory for a decoding code block. + */ +opj_bool tcd_code_block_dec_allocate (opj_tcd_cblk_dec_v2_t * p_code_block) { - OPJ_UINT32 l_data_read; + OPJ_UINT32 l_seg_size; + + if (! p_code_block->data) { + + p_code_block->data = (OPJ_BYTE*) opj_malloc(8192); + if (! p_code_block->data) { + return OPJ_FALSE; + } + /*fprintf(stderr, "Allocate 8192 elements of code_block->data\n");*/ + + l_seg_size = J2K_DEFAULT_NB_SEGS * sizeof(opj_tcd_seg_t); + p_code_block->segs = (opj_tcd_seg_t *) opj_malloc(l_seg_size); + if (! p_code_block->segs) { + return OPJ_FALSE; + } + memset(p_code_block->segs,0,l_seg_size); + /*fprintf(stderr, "Allocate %d elements of code_block->data\n", J2K_DEFAULT_NB_SEGS * sizeof(opj_tcd_seg_t));*/ + + p_code_block->m_current_max_segs = J2K_DEFAULT_NB_SEGS; + /*fprintf(stderr, "m_current_max_segs of code_block->data = %d\n", p_code_block->m_current_max_segs);*/ + } + /* TODO */ + /*p_code_block->numsegs = 0; */ + + return OPJ_TRUE; +} + +OPJ_UINT32 tcd_get_decoded_tile_size ( opj_tcd_v2_t *p_tcd ) +{ + OPJ_UINT32 i; + OPJ_UINT32 l_data_size = 0; + opj_image_comp_t * l_img_comp = 00; + opj_tcd_tilecomp_v2_t * l_tile_comp = 00; + opj_tcd_resolution_v2_t * l_res = 00; + OPJ_UINT32 l_size_comp, l_remaining; + + l_tile_comp = p_tcd->tcd_image->tiles->comps; + l_img_comp = p_tcd->image->comps; + + for (i=0;iimage->numcomps;++i) { + l_size_comp = l_img_comp->prec >> 3; /*(/ 8)*/ + l_remaining = l_img_comp->prec & 7; /* (%8) */ + + if(l_remaining) { + ++l_size_comp; + } + + if (l_size_comp == 3) { + l_size_comp = 4; + } + + l_res = l_tile_comp->resolutions + l_tile_comp->minimum_num_resolutions - 1; + l_data_size += l_size_comp * (l_res->x1 - l_res->x0) * (l_res->y1 - l_res->y0); + ++l_img_comp; + ++l_tile_comp; + } + + return l_data_size; +} + +opj_bool tcd_encode_tile_v2(opj_tcd_v2_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_v2_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_v2_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 */ + + /* FIXME _ProfStart(PGROUP_DC_SHIFT); */ + /*---------------TILE-------------------*/ + if (! tcd_dc_level_shift_encode(p_tcd)) { + return OPJ_FALSE; + } + /* FIXME _ProfStop(PGROUP_DC_SHIFT); */ + + /* FIXME _ProfStart(PGROUP_MCT); */ + if (! tcd_mct_encode(p_tcd)) { + return OPJ_FALSE; + } + /* FIXME _ProfStop(PGROUP_MCT); */ + + /* FIXME _ProfStart(PGROUP_DWT); */ + if (! tcd_dwt_encode(p_tcd)) { + return OPJ_FALSE; + } + /* FIXME _ProfStop(PGROUP_DWT); */ + + /* FIXME _ProfStart(PGROUP_T1); */ + if (! tcd_t1_encode(p_tcd)) { + return OPJ_FALSE; + } + /* FIXME _ProfStop(PGROUP_T1); */ + + /* FIXME _ProfStart(PGROUP_RATE); */ + if (! tcd_rate_allocate_encode(p_tcd,p_dest,p_max_length,p_cstr_info)) { + return OPJ_FALSE; + } + /* FIXME _ProfStop(PGROUP_RATE); */ + + } + /*--------------TIER2------------------*/ + + /* INDEX */ + if (p_cstr_info) { + p_cstr_info->index_write = 1; + } + /* FIXME _ProfStart(PGROUP_T2); */ + + if (! tcd_t2_encode(p_tcd,p_dest,p_data_written,p_max_length,p_cstr_info)) { + return OPJ_FALSE; + } + /* FIXME _ProfStop(PGROUP_T2); */ + + /*---------------CLEAN-------------------*/ + + return OPJ_TRUE; +} + +opj_bool tcd_decode_tile_v2( + opj_tcd_v2_t *p_tcd, + OPJ_BYTE *p_src, + OPJ_UINT32 p_max_length, + OPJ_UINT32 p_tile_no, + opj_codestream_index_t *p_cstr_index) +{ + OPJ_UINT32 l_data_read; p_tcd->tcd_tileno = p_tile_no; p_tcd->tcp = &(p_tcd->cp->tcps[p_tile_no]); @@ -2315,38 +2866,6 @@ void tcd_free_tile(opj_tcd_v2_t *p_tcd) } -/** - * Allocates memory for a decoding code block. - */ -opj_bool tcd_code_block_dec_allocate (opj_tcd_cblk_dec_v2_t * p_code_block) -{ - OPJ_UINT32 l_seg_size; - - if (! p_code_block->data) { - - p_code_block->data = (OPJ_BYTE*) opj_malloc(8192); - if (! p_code_block->data) { - return OPJ_FALSE; - } - /*fprintf(stderr, "Allocate 8192 elements of code_block->data\n");*/ - - l_seg_size = J2K_DEFAULT_NB_SEGS * sizeof(opj_tcd_seg_t); - p_code_block->segs = (opj_tcd_seg_t *) opj_malloc(l_seg_size); - if (! p_code_block->segs) { - return OPJ_FALSE; - } - memset(p_code_block->segs,0,l_seg_size); - /*fprintf(stderr, "Allocate %d elements of code_block->data\n", J2K_DEFAULT_NB_SEGS * sizeof(opj_tcd_seg_t));*/ - - p_code_block->m_current_max_segs = J2K_DEFAULT_NB_SEGS; - /*fprintf(stderr, "m_current_max_segs of code_block->data = %d\n", p_code_block->m_current_max_segs);*/ - } - /* TODO */ - /*p_code_block->numsegs = 0; */ - - return OPJ_TRUE; -} - opj_bool tcd_t2_decode ( opj_tcd_v2_t *p_tcd, OPJ_BYTE * p_src_data, @@ -2623,4 +3142,344 @@ void tcd_code_block_dec_deallocate (opj_tcd_precinct_v2_t * p_precinct) } } +OPJ_UINT32 tcd_get_encoded_tile_size ( opj_tcd_v2_t *p_tcd ) +{ + OPJ_UINT32 i,l_data_size = 0; + opj_image_comp_t * l_img_comp = 00; + opj_tcd_tilecomp_v2_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;iimage->numcomps;++i) { + l_size_comp = l_img_comp->prec >> 3; /*(/ 8)*/ + l_remaining = l_img_comp->prec & 7; /* (%8) */ + + if (l_remaining) { + ++l_size_comp; + } + + if (l_size_comp == 3) { + l_size_comp = 4; + } + + l_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; +} + +opj_bool tcd_dc_level_shift_encode ( opj_tcd_v2_t *p_tcd ) +{ + OPJ_UINT32 compno; + opj_tcd_tilecomp_v2_t * l_tile_comp = 00; + opj_tccp_t * l_tccp = 00; + opj_image_comp_t * l_img_comp = 00; + opj_tcp_v2_t * l_tcp = 00; + opj_tcd_tile_v2_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; + } + } + 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; + } + } + + ++l_img_comp; + ++l_tccp; + ++l_tile_comp; + } + + return OPJ_TRUE; +} + +opj_bool tcd_mct_encode ( opj_tcd_v2_t *p_tcd ) +{ + opj_tcd_tile_v2_t * l_tile = p_tcd->tcd_image->tiles; + opj_tcd_tilecomp_v2_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_v2_t * l_tcp = p_tcd->tcp; + + if(!p_tcd->tcp->mct) { + return OPJ_TRUE; + } + + if (p_tcd->tcp->mct == 2) { + if (! p_tcd->tcp->m_mct_coding_matrix) { + return OPJ_TRUE; + } + + l_data = (OPJ_BYTE **) opj_malloc(l_tile->numcomps*sizeof(OPJ_BYTE*)); + if (! l_data) { + return OPJ_FALSE; + } + + for (i=0;inumcomps;++i) { + l_data[i] = (OPJ_BYTE*) l_tile_comp->data; + ++l_tile_comp; + } + + if (! mct_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 OPJ_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 OPJ_TRUE; +} + +opj_bool tcd_dwt_encode ( opj_tcd_v2_t *p_tcd ) +{ + opj_tcd_tile_v2_t * l_tile = p_tcd->tcd_image->tiles; + opj_tcd_tilecomp_v2_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_v2(l_tile_comp)) { + return OPJ_FALSE; + } + } + else if (l_tccp->qmfbid == 0) { + if (! dwt_encode_real_v2(l_tile_comp)) { + return OPJ_FALSE; + } + } + + ++l_tile_comp; + ++l_tccp; + } + + return OPJ_TRUE; +} + +opj_bool tcd_t1_encode ( opj_tcd_v2_t *p_tcd ) +{ + opj_t1_t * l_t1; + const OPJ_FLOAT64 * l_mct_norms; + opj_tcp_v2_t * l_tcp = p_tcd->tcp; + + l_t1 = t1_create_v2(); + if (l_t1 == 00) { + return OPJ_FALSE; + } + + if (l_tcp->mct == 1) { + // irreversible encoding + if (l_tcp->tccps->qmfbid == 0) { + l_mct_norms = get_mct_norms_real(); + } + else { + l_mct_norms = get_mct_norms(); + } + } + else { + l_mct_norms = (const OPJ_FLOAT64 *) (l_tcp->mct_norms); + } + + if (! t1_encode_cblks_v2(l_t1, p_tcd->tcd_image->tiles , l_tcp, l_mct_norms)) { + t1_destroy_v2(l_t1); + return OPJ_FALSE; + } + + t1_destroy_v2(l_t1); + + return OPJ_TRUE; +} + +opj_bool tcd_t2_encode (opj_tcd_v2_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_v2_t * l_t2; + + l_t2 = t2_create_v2(p_tcd->image, p_tcd->cp); + if (l_t2 == 00) { + return OPJ_FALSE; + } + + if (! t2_encode_packets_v2( + 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_v2(l_t2); + return OPJ_FALSE; + } + + t2_destroy_v2(l_t2); + + /*---------------CLEAN-------------------*/ + return OPJ_TRUE; +} + + +opj_bool tcd_rate_allocate_encode( opj_tcd_v2_t *p_tcd, + OPJ_BYTE * p_dest_data, + OPJ_UINT32 p_max_dest_size, + opj_codestream_info_t *p_cstr_info ) +{ + opj_cp_v2_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_v2(p_tcd, p_dest_data,&l_nb_written, p_max_dest_size, p_cstr_info)) { + return OPJ_FALSE; + } + } + else { + /* Fixed layer allocation */ + tcd_rateallocate_fixed_v2(p_tcd); + } + + return OPJ_TRUE; +} + + +opj_bool tcd_copy_tile_data ( opj_tcd_v2_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_v2_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 OPJ_FALSE; + } + + l_tilec = p_tcd->tcd_image->tiles->comps; + l_img_comp = p_tcd->image->comps; + for (i=0;iimage->numcomps;++i) { + l_size_comp = l_img_comp->prec >> 3; /*(/ 8)*/ + l_remaining = l_img_comp->prec & 7; /* (%8) */ + l_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;jdata; + OPJ_INT16 * l_src_ptr = (OPJ_INT16 *) p_src; + + if (l_img_comp->sgnd) { + for (j=0;jdata; + + for (j=0;j