diff --git a/CMakeLists.txt b/CMakeLists.txt index b014a00fd..f7d5d254a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -250,6 +250,7 @@ add_subdirectory(src/lib) #----------------------------------------------------------------------------- # Build Applications option(BUILD_CODEC "Build the CODEC executables" ON) +option(BUILD_WITH_OPENMP "Build the OpenMP support." OFF) option(BUILD_MJ2 "Build the MJ2 executables." OFF) option(BUILD_JPWL "Build the JPWL library and executables" OFF) option(BUILD_JPIP "Build the JPIP library and executables." OFF) diff --git a/src/bin/common/color.c b/src/bin/common/color.c index 0f2b8daca..1f8194c20 100644 --- a/src/bin/common/color.c +++ b/src/bin/common/color.c @@ -57,6 +57,31 @@ #define OPJ_CLRSPC_SRGB CLRSPC_SRGB #endif + + +static opj_image_t* image_create(OPJ_UINT32 numcmpts, OPJ_UINT32 w, OPJ_UINT32 h, OPJ_UINT32 prec) { + opj_image_cmptparm_t* cmptparms = (opj_image_cmptparm_t*)calloc(numcmpts, sizeof(opj_image_cmptparm_t)); + opj_image_t* img = NULL; + OPJ_UINT32 compno=0; + for (compno = 0; compno < numcmpts; ++compno) { + memset(cmptparms + compno, 0, sizeof(opj_image_cmptparm_t)); + cmptparms[compno].dx = 1; + cmptparms[compno].dy = 1; + cmptparms[compno].w = w; + cmptparms[compno].h = h; + cmptparms[compno].x0 = 0; + cmptparms[compno].y0 = 0; + cmptparms[compno].prec = prec; + cmptparms[compno].bpp = prec; + cmptparms[compno].sgnd = 0; + } + img = opj_image_create(numcmpts, (opj_image_cmptparm_t *)cmptparms, OPJ_CLRSPC_SRGB); + free(cmptparms); + return img; + +} + + /*-------------------------------------------------------- Matrix for sYCC, Amendment 1 to IEC 61966-2-1 @@ -93,6 +118,7 @@ static void sycc444_to_rgb(opj_image_t *img) const int *y, *cb, *cr; unsigned int maxw, maxh, max, i; int offset, upb; + opj_image_t* new_image = image_create(3, img->comps[0].w, img->comps[0].h, img->comps[0].prec); upb = (int)img->comps[0].prec; offset = 1<<(upb - 1); upb = (1<comps[1].data; cr = img->comps[2].data; - d0 = r = (int*)malloc(sizeof(int) * (size_t)max); - d1 = g = (int*)malloc(sizeof(int) * (size_t)max); - d2 = b = (int*)malloc(sizeof(int) * (size_t)max); + d0 = r = new_image->comps[0].data; + d1 = g = new_image->comps[1].data; + d2 = b = new_image->comps[2].data; + + new_image->comps[0].data = NULL; + new_image->comps[1].data = NULL; + new_image->comps[2].data = NULL; + + opj_image_destroy(new_image); + new_image = NULL; for(i = 0U; i < max; ++i) { sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); ++y; ++cb; ++cr; ++r; ++g; ++b; } - free(img->comps[0].data); img->comps[0].data = d0; - free(img->comps[1].data); img->comps[1].data = d1; - free(img->comps[2].data); img->comps[2].data = d2; + opj_image_all_components_data_free(img); + img->comps[0].data = d0; + img->comps[1].data = d1; + img->comps[2].data = d2; }/* sycc444_to_rgb() */ @@ -123,25 +157,33 @@ static void sycc422_to_rgb(opj_image_t *img) { int *d0, *d1, *d2, *r, *g, *b; const int *y, *cb, *cr; - unsigned int maxw, maxh, max; + unsigned int maxw, maxh; int offset, upb; unsigned int i, j; + opj_image_t* new_image = image_create(3, img->comps[0].w, img->comps[0].h, img->comps[0].prec); upb = (int)img->comps[0].prec; offset = 1<<(upb - 1); upb = (1<comps[0].w; maxh = (unsigned int)img->comps[0].h; - max = maxw * maxh; + maxw = (unsigned int)img->comps[0].w; + maxh = (unsigned int)img->comps[0].h; y = img->comps[0].data; cb = img->comps[1].data; cr = img->comps[2].data; - d0 = r = (int*)malloc(sizeof(int) * (size_t)max); - d1 = g = (int*)malloc(sizeof(int) * (size_t)max); - d2 = b = (int*)malloc(sizeof(int) * (size_t)max); + d0 = r = new_image->comps[0].data; + d1 = g = new_image->comps[1].data; + d2 = b = new_image->comps[2].data; + + new_image->comps[0].data = NULL; + new_image->comps[1].data = NULL; + new_image->comps[2].data = NULL; - for(i=0U; i < maxh; ++i) + opj_image_destroy(new_image); + new_image = NULL; + + for (i = 0U; i < maxh; ++i) { for(j=0U; j < (maxw & ~(unsigned int)1U); j += 2U) { @@ -155,9 +197,10 @@ static void sycc422_to_rgb(opj_image_t *img) ++y; ++r; ++g; ++b; ++cb; ++cr; } } - free(img->comps[0].data); img->comps[0].data = d0; - free(img->comps[1].data); img->comps[1].data = d1; - free(img->comps[2].data); img->comps[2].data = d2; + opj_image_all_components_data_free(img); + img->comps[0].data = d0; + img->comps[1].data = d1; + img->comps[2].data = d2; #if defined(USE_JPWL) || defined(USE_MJ2) img->comps[1].w = maxw; img->comps[1].h = maxh; @@ -177,25 +220,33 @@ static void sycc420_to_rgb(opj_image_t *img) { int *d0, *d1, *d2, *r, *g, *b, *nr, *ng, *nb; const int *y, *cb, *cr, *ny; - unsigned int maxw, maxh, max; + unsigned int maxw, maxh; int offset, upb; unsigned int i, j; + opj_image_t* new_image = image_create(3, img->comps[0].w, img->comps[0].h, img->comps[0].prec); upb = (int)img->comps[0].prec; offset = 1<<(upb - 1); upb = (1<comps[0].w; maxh = (unsigned int)img->comps[0].h; - max = maxw * maxh; + maxw = (unsigned int)img->comps[0].w; + maxh = (unsigned int)img->comps[0].h; y = img->comps[0].data; cb = img->comps[1].data; cr = img->comps[2].data; - d0 = r = (int*)malloc(sizeof(int) * (size_t)max); - d1 = g = (int*)malloc(sizeof(int) * (size_t)max); - d2 = b = (int*)malloc(sizeof(int) * (size_t)max); + d0 = r = new_image->comps[0].data; + d1 = g = new_image->comps[1].data; + d2 = b = new_image->comps[2].data; - for(i=0U; i < (maxh & ~(unsigned int)1U); i += 2U) + new_image->comps[0].data = NULL; + new_image->comps[1].data = NULL; + new_image->comps[2].data = NULL; + + opj_image_destroy(new_image); + new_image = NULL; + + for (i = 0U; i < (maxh & ~(unsigned int)1U); i += 2U) { ny = y + maxw; nr = r + maxw; ng = g + maxw; nb = b + maxw; @@ -239,10 +290,10 @@ static void sycc420_to_rgb(opj_image_t *img) sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); } } - - free(img->comps[0].data); img->comps[0].data = d0; - free(img->comps[1].data); img->comps[1].data = d1; - free(img->comps[2].data); img->comps[2].data = d2; + opj_image_all_components_data_free(img); + img->comps[0].data = d0; + img->comps[1].data = d1; + img->comps[2].data = d2; #if defined(USE_JPWL) || defined(USE_MJ2) img->comps[1].w = maxw; img->comps[1].h = maxh; @@ -332,6 +383,7 @@ void color_apply_icc_profile(opj_image_t *image) int *r, *g, *b; int prec, i, max, max_w, max_h; OPJ_COLOR_SPACE oldspace; + opj_image_t* new_image = NULL; in_prof = cmsOpenProfileFromMem(image->icc_profile_buf, image->icc_profile_len); @@ -520,8 +572,8 @@ fprintf(stderr,"%s:%d:color_apply_icc_profile\n\tcmsCreateTransform failed. " in = inbuf = (unsigned char*)malloc(nr_samples); out = outbuf = (unsigned char*)malloc(nr_samples); - image->comps = (opj_image_comp_t*) - realloc(image->comps, (image->numcomps+2)*sizeof(opj_image_comp_t)); + new_image = image_create(2, image->comps[0].w, image->comps[0].h, image->comps[0].prec); + image->comps = (opj_image_comp_t*)realloc(image->comps, (image->numcomps + 2)*sizeof(opj_image_comp_t)); if(image->numcomps == 2) image->comps[3] = image->comps[1]; @@ -529,8 +581,14 @@ fprintf(stderr,"%s:%d:color_apply_icc_profile\n\tcmsCreateTransform failed. " image->comps[1] = image->comps[0]; image->comps[2] = image->comps[0]; - image->comps[1].data = (int*)calloc((size_t)max, sizeof(int)); - image->comps[2].data = (int*)calloc((size_t)max, sizeof(int)); + image->comps[1].data = new_image->comps[0].data; + image->comps[2].data = new_image->comps[1].data; + + new_image->comps[0].data= NULL; + new_image->comps[1].data = NULL; + + opj_image_destroy(new_image); + new_image = NULL; image->numcomps += 2; @@ -593,7 +651,8 @@ void color_cielab_to_rgb(opj_image_t *image) cmsHTRANSFORM transform; cmsUInt16Number RGB[3]; cmsCIELab Lab; - + opj_image_t* new_image = image_create(3, image->comps[0].w, image->comps[0].h, image->comps[0].prec); + in = cmsCreateLab4Profile(NULL); out = cmsCreate_sRGBProfile(); @@ -635,12 +694,19 @@ void color_cielab_to_rgb(opj_image_t *image) b = src2 = image->comps[2].data; max = image->comps[0].w * image->comps[0].h; - - red = dst0 = (int*)malloc(max * sizeof(int)); - green = dst1 = (int*)malloc(max * sizeof(int)); - blue = dst2 = (int*)malloc(max * sizeof(int)); - - minL = -(rl * ol)/(pow(2, prec0)-1); + + red = dst0 = new_image->comps[0].data; + green = dst1 = new_image->comps[1].data; + blue = dst2 = new_image->comps[2].data; + + new_image->comps[0].data=NULL; + new_image->comps[1].data=NULL; + new_image->comps[2].data=NULL; + + opj_image_destroy(new_image); + new_image = NULL; + + minL = -(rl * ol) / (pow(2, prec0) - 1); maxL = minL + rl; mina = -(ra * oa)/(pow(2, prec1)-1); @@ -666,10 +732,11 @@ void color_cielab_to_rgb(opj_image_t *image) cmsCloseProfile(in); cmsCloseProfile(out); #endif - free(src0); image->comps[0].data = dst0; - free(src1); image->comps[1].data = dst1; - free(src2); image->comps[2].data = dst2; - + opj_image_all_components_data_free(image); + image->comps[0].data = dst0; + image->comps[1].data = dst1; + image->comps[2].data = dst2; + image->color_space = OPJ_CLRSPC_SRGB; image->comps[0].prec = 16; image->comps[1].prec = 16; @@ -721,7 +788,7 @@ void color_cmyk_to_rgb(opj_image_t *image) image->comps[2].data[i] = (int)(255.0F * Y * K); /* B */ } - free(image->comps[3].data); image->comps[3].data = NULL; + opj_image_single_component_data_free(image->comps + 3); image->comps[0].prec = 8; image->comps[1].prec = 8; image->comps[2].prec = 8; diff --git a/src/bin/jp2/CMakeLists.txt b/src/bin/jp2/CMakeLists.txt index d583c2e6b..ab0729318 100644 --- a/src/bin/jp2/CMakeLists.txt +++ b/src/bin/jp2/CMakeLists.txt @@ -1,5 +1,15 @@ # Build the demo app, small examples + +if (BUILD_WITH_OPENMP) +find_package(OpenMP) +if (OPENMP_FOUND) + add_definitions(-DOPJ_NUM_COMPRESS_DECOMPRESS_THREADS=4) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") +endif() +endif() + # First thing define the common source: set(common_SRCS convert.c diff --git a/src/bin/jp2/opj_compress.c b/src/bin/jp2/opj_compress.c index 9d690a567..f2a5d2a32 100644 --- a/src/bin/jp2/opj_compress.c +++ b/src/bin/jp2/opj_compress.c @@ -71,6 +71,11 @@ #include "format_defs.h" #include "opj_string.h" +#ifdef _OPENMP +#include +#endif + + typedef struct dircnt{ /** Buffer for holding images read from Directory*/ char *filename_buf; @@ -447,8 +452,8 @@ static char * get_file_name(char *name){ return fname; } -static char get_next_file(int imageno,dircnt_t *dirptr,img_fol_t *img_fol, opj_cparameters_t *parameters){ - char image_filename[OPJ_PATH_LEN], infilename[OPJ_PATH_LEN],outfilename[OPJ_PATH_LEN],temp_ofname[OPJ_PATH_LEN]; +static char get_next_file(int imageno,dircnt_t *dirptr,img_fol_t *img_fol, opj_cparameters_t *parameters, char* infilename, char* outfilename){ + char image_filename[OPJ_PATH_LEN], temp_ofname[OPJ_PATH_LEN]; char *temp_p, temp1[OPJ_PATH_LEN]=""; strcpy(image_filename,dirptr->filename[imageno]); @@ -1575,7 +1580,7 @@ OPJ_FLOAT64 opj_clock(void) { /* cout << "freq = " << ((double) freq.QuadPart) << endl; */ /* t is the high resolution performance counter (see MSDN) */ QueryPerformanceCounter ( & t ) ; - return freq.QuadPart ? ( t.QuadPart /(OPJ_FLOAT64) freq.QuadPart ) : 0 ; + return freq.QuadPart ? ((OPJ_FLOAT64)t.QuadPart /(OPJ_FLOAT64) freq.QuadPart ) : 0 ; #else /* Unix or Linux: use resource usage */ struct rusage t; @@ -1599,23 +1604,19 @@ OPJ_FLOAT64 opj_clock(void) { int main(int argc, char **argv) { opj_cparameters_t parameters; /* compression parameters */ - - opj_stream_t *l_stream = 00; - opj_codec_t* l_codec = 00; - opj_image_t *image = NULL; raw_cparameters_t raw_cp; OPJ_SIZE_T num_compressed_files = 0; char indexfilename[OPJ_PATH_LEN]; /* index file name */ - unsigned int i, num_images, imageno; + OPJ_INT32 i,num_images; + OPJ_INT32 imageno; img_fol_t img_fol; dircnt_t *dirptr = NULL; - OPJ_BOOL bSuccess; - OPJ_BOOL bUseTiles = OPJ_FALSE; /* OPJ_TRUE */ - OPJ_UINT32 l_nb_tiles = 4; - OPJ_FLOAT64 t = opj_clock(); + + OPJ_FLOAT64 t ; + OPJ_INT32 rc = 0; /* set encoding parameters to default values */ opj_set_default_encoder_parameters(¶meters); @@ -1662,236 +1663,290 @@ int main(int argc, char **argv) { }else{ num_images=1; } - /*Encoding image one by one*/ - for(imageno=0;imagenonumcomps >= 3) ? 1 : 0; - } else { /* mct mode has been set in commandline */ - if ((parameters.tcp_mct == 1) && (image->numcomps < 3)){ - fprintf(stderr, "RGB->YCC conversion cannot be used:\n"); - fprintf(stderr, "Input image has less than 3 components\n"); - return 1; - } - if ((parameters.tcp_mct == 2) && (!parameters.mct_data)){ - fprintf(stderr, "Custom MCT has been set but no array-based MCT\n"); - fprintf(stderr, "has been provided. Aborting.\n"); - return 1; - } - } - - /* encode the destination image */ - /* ---------------------------- */ - - switch(parameters.cod_format) { - case J2K_CFMT: /* JPEG-2000 codestream */ - { - /* Get a decoder handle */ - l_codec = opj_create_compress(OPJ_CODEC_J2K); - break; - } - case JP2_CFMT: /* JPEG 2000 compressed image data */ - { - /* Get a decoder handle */ - l_codec = opj_create_compress(OPJ_CODEC_JP2); - break; - } - default: - fprintf(stderr, "skipping file..\n"); - opj_stream_destroy(l_stream); - continue; - } - - /* catch events using our callbacks and give a local context */ - opj_set_info_handler(l_codec, info_callback,00); - opj_set_warning_handler(l_codec, warning_callback,00); - opj_set_error_handler(l_codec, error_callback,00); - - if( bUseTiles ) { - parameters.cp_tx0 = 0; - parameters.cp_ty0 = 0; - parameters.tile_size_on = OPJ_TRUE; - parameters.cp_tdx = 512; - parameters.cp_tdy = 512; - } - if (! opj_setup_encoder(l_codec, ¶meters, image)) { - fprintf(stderr, "failed to encode image: opj_setup_encoder\n"); - opj_destroy_codec(l_codec); - opj_image_destroy(image); - return 1; - } - - /* open a byte stream for writing and allocate memory for all tiles */ - l_stream = opj_stream_create_default_file_stream(parameters.outfile,OPJ_FALSE); - if (! l_stream){ - return 1; - } - - /* encode the image */ - bSuccess = opj_start_compress(l_codec,image,l_stream); - if (!bSuccess) { - fprintf(stderr, "failed to encode image: opj_start_compress\n"); - } - if( bSuccess && bUseTiles ) { - OPJ_BYTE *l_data; - OPJ_UINT32 l_data_size = 512*512*3; - l_data = (OPJ_BYTE*) calloc( 1,l_data_size); - assert( l_data ); - for (i=0;i test_tile_encoder: failed to write the tile %d!\n",i); - opj_stream_destroy(l_stream); - opj_destroy_codec(l_codec); - opj_image_destroy(image); - return 1; - } - } - free(l_data); - } - else { - bSuccess = bSuccess && opj_encode(l_codec, l_stream); - if (!bSuccess) { - fprintf(stderr, "failed to encode image: opj_encode\n"); - } - } - bSuccess = bSuccess && opj_end_compress(l_codec, l_stream); - if (!bSuccess) { - fprintf(stderr, "failed to encode image: opj_end_compress\n"); - } + } + + /* Can happen if input file is TIFF or PNG + * and OPJ_HAVE_LIBTIF or OPJ_HAVE_LIBPNG is undefined + */ + if (!image) { + fprintf(stderr, "Unable to load file: got no image\n"); + rc = 1; + continue; + } + + /* Decide if MCT should be used */ + if (parameters.tcp_mct == (char)255) { /* mct mode has not been set in commandline */ + parameters.tcp_mct = (image->numcomps >= 3) ? 1 : 0; + } + else { /* mct mode has been set in commandline */ + if ((parameters.tcp_mct == 1) && (image->numcomps < 3)) { + fprintf(stderr, "RGB->YCC conversion cannot be used:\n"); + fprintf(stderr, "Input image has less than 3 components\n"); + rc = 1; + continue; + } + if ((parameters.tcp_mct == 2) && (!parameters.mct_data)) { + fprintf(stderr, "Custom MCT has been set but no array-based MCT\n"); + fprintf(stderr, "has been provided. Aborting.\n"); + rc = 1; + continue; + } + } + + /* encode the destination image */ + /* ---------------------------- */ + + switch (parameters.cod_format) { + case J2K_CFMT: /* JPEG-2000 codestream */ + { + /* Get a decoder handle */ + l_codec = opj_create_compress(OPJ_CODEC_J2K); + break; + } + case JP2_CFMT: /* JPEG 2000 compressed image data */ + { + /* Get a decoder handle */ + l_codec = opj_create_compress(OPJ_CODEC_JP2); + break; + } + default: + fprintf(stderr, "skipping file..\n"); + opj_stream_destroy(l_stream); + continue; + } + + /* catch events using our callbacks and give a local context */ + opj_set_info_handler(l_codec, info_callback, 00); + opj_set_warning_handler(l_codec, warning_callback, 00); + opj_set_error_handler(l_codec, error_callback, 00); + + if (bUseTiles) { + parameters.cp_tx0 = 0; + parameters.cp_ty0 = 0; + parameters.tile_size_on = OPJ_TRUE; + parameters.cp_tdx = 512; + parameters.cp_tdy = 512; + } + if (!opj_setup_encoder(l_codec, ¶meters, image)) { + fprintf(stderr, "failed to encode image: opj_setup_encoder\n"); + opj_destroy_codec(l_codec); + opj_image_destroy(image); + rc = 1; + continue; + } + + /* open a byte stream for writing and allocate memory for all tiles */ + l_stream = opj_stream_create_default_file_stream(outfile, OPJ_FALSE); + if (!l_stream) { + rc = 1; + continue; + } + + /* encode the image */ + bSuccess = opj_start_compress(l_codec, image, l_stream); + if (!bSuccess) { + fprintf(stderr, "failed to encode image: opj_start_compress\n"); + } + if (bSuccess && bUseTiles) { + OPJ_UINT32 i; + OPJ_BYTE *l_data; + OPJ_UINT32 l_data_size = 512 * 512 * 3; + l_data = (OPJ_BYTE*)calloc(1, l_data_size); + assert(l_data); + for (i = 0; i < l_nb_tiles; ++i) { + if (!opj_write_tile(l_codec, i, l_data, l_data_size, l_stream)) { + fprintf(stderr, "ERROR -> test_tile_encoder: failed to write the tile %d!\n", i); + opj_stream_destroy(l_stream); + opj_destroy_codec(l_codec); + opj_image_destroy(image); + rc = 1; + continue; + } + } + free(l_data); + } + else { + bSuccess = bSuccess && opj_encode(l_codec, l_stream); + if (!bSuccess) { + fprintf(stderr, "failed to encode image: opj_encode\n"); + } + } + bSuccess = bSuccess && opj_end_compress(l_codec, l_stream); + if (!bSuccess) { + fprintf(stderr, "failed to encode image: opj_end_compress\n"); + } + + if (!bSuccess) { + opj_stream_destroy(l_stream); + opj_destroy_codec(l_codec); + opj_image_destroy(image); + fprintf(stderr, "failed to encode image\n"); + remove(parameters.outfile); + rc = 1; + continue; + } + +#ifdef _OPENMP +#pragma omp atomic +#endif + num_compressed_files++; - if (!bSuccess) { - opj_stream_destroy(l_stream); - opj_destroy_codec(l_codec); - opj_image_destroy(image); - fprintf(stderr, "failed to encode image\n"); - remove(parameters.outfile); - return 1; - } + fprintf(stdout, "[INFO] Generated outfile %s\n", parameters.outfile); + /* close and free the byte stream */ + opj_stream_destroy(l_stream); - num_compressed_files++; - fprintf(stdout,"[INFO] Generated outfile %s\n",parameters.outfile); - /* close and free the byte stream */ - opj_stream_destroy(l_stream); + /* free remaining compression structures */ + opj_destroy_codec(l_codec); - /* free remaining compression structures */ - opj_destroy_codec(l_codec); + /* free image data */ + opj_image_destroy(image); - /* free image data */ - opj_image_destroy(image); + } - } +#ifdef _OPENMP + } +#endif /* free user parameters structure */ if(parameters.cp_comment) free(parameters.cp_comment); @@ -1902,6 +1957,6 @@ int main(int argc, char **argv) { if (num_compressed_files) { fprintf(stdout, "encode time: %d ms \n", (int)((t * 1000.0)/(OPJ_FLOAT64)num_compressed_files)); } - - return 0; + //getchar(); + return rc; } diff --git a/src/bin/jp2/opj_decompress.c b/src/bin/jp2/opj_decompress.c index f3b1cd5c9..8dd4fbd06 100644 --- a/src/bin/jp2/opj_decompress.c +++ b/src/bin/jp2/opj_decompress.c @@ -39,6 +39,11 @@ */ #include "opj_apps_config.h" +#ifdef _OPENMP +#include +#endif + + #include #include #include @@ -157,7 +162,7 @@ typedef struct opj_decompress_params int get_num_images(char *imgdirpath); int load_images(dircnt_t *dirptr, char *imgdirpath); int get_file_format(const char *filename); -char get_next_file(int imageno,dircnt_t *dirptr,img_fol_t *img_fol, opj_decompress_parameters *parameters); +char get_next_file(int imageno,dircnt_t *dirptr,img_fol_t *img_fol, int* decod_format, char* infilename, char* outfilename); static int infile_format(const char *fname); int parse_cmdline_decoder(int argc, char **argv, opj_decompress_parameters *parameters,img_fol_t *img_fol); @@ -422,19 +427,16 @@ const char* path_separator = "/"; #endif /* -------------------------------------------------------------------------- */ -char get_next_file(int imageno,dircnt_t *dirptr,img_fol_t *img_fol, opj_decompress_parameters *parameters){ - char image_filename[OPJ_PATH_LEN], infilename[OPJ_PATH_LEN],outfilename[OPJ_PATH_LEN],temp_ofname[OPJ_PATH_LEN]; +char get_next_file(int imageno,dircnt_t *dirptr,img_fol_t *img_fol, int* decod_format, char* infilename, char* outfilename){ + char image_filename[OPJ_PATH_LEN], temp_ofname[OPJ_PATH_LEN]; char *temp_p, temp1[OPJ_PATH_LEN]=""; strcpy(image_filename,dirptr->filename[imageno]); fprintf(stderr,"File Number %d \"%s\"\n",imageno,image_filename); sprintf(infilename, "%s%s%s", img_fol->imgdirpath, path_separator, image_filename); - parameters->decod_format = infile_format(infilename); - if (parameters->decod_format == -1) - return 1; - if (opj_strcpy_s(parameters->infile, sizeof(parameters->infile), infilename) != 0) { + *decod_format = infile_format(infilename); + if (*decod_format == -1) return 1; - } /*Set output file*/ strcpy(temp_ofname,strtok(image_filename,".")); @@ -444,9 +446,6 @@ char get_next_file(int imageno,dircnt_t *dirptr,img_fol_t *img_fol, opj_decompre } if(img_fol->set_out_format==1){ sprintf(outfilename,"%s/%s.%s",img_fol->imgdirpath,temp_ofname,img_fol->out_format); - if (opj_strcpy_s(parameters->outfile, sizeof(parameters->outfile), outfilename) != 0) { - return 1; - } } return 0; } @@ -881,7 +880,7 @@ OPJ_FLOAT64 opj_clock(void) { /* cout << "freq = " << ((double) freq.QuadPart) << endl; */ /* t is the high resolution performance counter (see MSDN) */ QueryPerformanceCounter ( & t ) ; - return freq.QuadPart ? (t.QuadPart / (OPJ_FLOAT64)freq.QuadPart) : 0; + return freq.QuadPart ? ((OPJ_FLOAT64)t.QuadPart / (OPJ_FLOAT64)freq.QuadPart) : 0; #else /* Unix or Linux: use resource usage */ struct rusage t; @@ -1172,25 +1171,23 @@ static opj_image_t* upsample_image_components(opj_image_t* original) return l_new_image; } +OPJ_BOOL store_file_to_disk = OPJ_TRUE; + /* -------------------------------------------------------------------------- */ /** * OPJ_DECOMPRESS MAIN */ /* -------------------------------------------------------------------------- */ + int main(int argc, char **argv) { opj_decompress_parameters parameters; /* decompression parameters */ - opj_image_t* image = NULL; - opj_stream_t *l_stream = NULL; /* Stream */ - opj_codec_t* l_codec = NULL; /* Handle to a decompressor */ - opj_codestream_index_t* cstr_index = NULL; - OPJ_INT32 num_images, imageno; img_fol_t img_fol; dircnt_t *dirptr = NULL; - int failed = 0; - OPJ_FLOAT64 t, tCumulative = 0; - OPJ_UINT32 numDecompressedImages = 0; + int failed = 0; + OPJ_FLOAT64 t_cumulative = 0; + OPJ_UINT32 num_decompressed_images = 0; /* set decoding parameters to default values */ set_default_parameters(¶meters); @@ -1235,33 +1232,63 @@ int main(int argc, char **argv) num_images=1; } - /*Decoding image one by one*/ - for(imageno = 0; imageno < num_images ; imageno++) { +#ifdef _OPENMP + omp_set_num_threads(OPJ_NUM_COMPRESS_DECOMPRESS_THREADS); +#endif - fprintf(stderr,"\n"); + opj_initialize(); - if(img_fol.set_imgdir==1){ - if (get_next_file(imageno, dirptr,&img_fol, ¶meters)) { - fprintf(stderr,"skipping file...\n"); - destroy_parameters(¶meters); - continue; + t_cumulative = opj_clock(); +#ifdef _OPENMP +#ifdef _WIN32 +#pragma omp parallel default(none) private(imageno) shared(num_images,img_fol, dirptr, parameters, failed,store_file_to_disk,num_decompressed_images) +#else +#pragma omp parallel default(none) private(imageno) shared(stdout, stderr, num_images,img_fol, dirptr, parameters, failed,store_file_to_disk,num_decompressed_images) +#endif + { +#pragma omp for +#endif + + /*Decoding image one by one*/ + for (imageno = 0; imageno < num_images; imageno++) { + + opj_image_t* image = NULL; + opj_stream_t *l_stream = NULL; /* Stream */ + opj_codec_t* l_codec = NULL; /* Handle to a decompressor */ + opj_codestream_index_t* cstr_index = NULL; + char infile[OPJ_PATH_LEN], outfile[OPJ_PATH_LEN]; + int decod_format = -1; + + fprintf(stderr, "\n"); + if (img_fol.set_imgdir == 1) { + if (get_next_file(imageno, dirptr, &img_fol, &decod_format, infile, outfile)) { + fprintf(stderr, "skipping file...\n"); + goto cleanup; + } + } + else { + strncpy(infile, parameters.infile, sizeof(parameters.infile)); + strncpy(outfile, parameters.outfile, sizeof(parameters.outfile)); } - } - /* read the input file and put it in memory */ - /* ---------------------------------------- */ + /* read the input file and put it in memory */ + /* ---------------------------------------- */ + if (!l_stream) { + l_stream = opj_stream_create_mapped_file_read_stream(infile); + } - l_stream = opj_stream_create_default_file_stream(parameters.infile,1); - if (!l_stream){ - fprintf(stderr, "ERROR -> failed to create the stream from the file %s\n", parameters.infile); - destroy_parameters(¶meters); - return EXIT_FAILURE; - } + + if (!l_stream) { + fprintf(stderr, "ERROR -> failed to create the stream from the file %s\n", infile); + failed = 1; + goto cleanup; + + } - /* decode the JPEG2000 stream */ - /* ---------------------- */ + /* decode the JPEG2000 stream */ + /* ---------------------- */ - switch(parameters.decod_format) { + switch (decod_format) { case J2K_CFMT: /* JPEG-2000 codestream */ { /* Get a decoder handle */ @@ -1282,136 +1309,125 @@ int main(int argc, char **argv) } default: fprintf(stderr, "skipping file..\n"); - destroy_parameters(¶meters); - opj_stream_destroy(l_stream); - continue; - } + goto cleanup; + } - /* catch events using our callbacks and give a local context */ - opj_set_info_handler(l_codec, info_callback,00); - opj_set_warning_handler(l_codec, warning_callback,00); - opj_set_error_handler(l_codec, error_callback,00); + /* catch events using our callbacks and give a local context */ + opj_set_info_handler(l_codec, info_callback, 00); + opj_set_warning_handler(l_codec, warning_callback, 00); + opj_set_error_handler(l_codec, error_callback, 00); - t = opj_clock(); + /* Setup the decoder decoding parameters using user parameters */ + if (!opj_setup_decoder(l_codec, &(parameters.core))) { + fprintf(stderr, "ERROR -> opj_decompress: failed to setup the decoder\n"); + failed = 1; + goto cleanup; + } - /* Setup the decoder decoding parameters using user parameters */ - if ( !opj_setup_decoder(l_codec, &(parameters.core)) ){ - fprintf(stderr, "ERROR -> opj_decompress: failed to setup the decoder\n"); - destroy_parameters(¶meters); - opj_stream_destroy(l_stream); - opj_destroy_codec(l_codec); - return EXIT_FAILURE; - } + /* Read the main header of the codestream and if necessary the JP2 boxes*/ + if (!opj_read_header(l_stream, l_codec, &image)) { + fprintf(stderr, "ERROR -> opj_decompress: failed to read the header\n"); + failed = 1; + goto cleanup; + } - /* Read the main header of the codestream and if necessary the JP2 boxes*/ - if(! opj_read_header(l_stream, l_codec, &image)){ - fprintf(stderr, "ERROR -> opj_decompress: failed to read the header\n"); - destroy_parameters(¶meters); - opj_stream_destroy(l_stream); - opj_destroy_codec(l_codec); - opj_image_destroy(image); - return EXIT_FAILURE; - } + if (!parameters.nb_tile_to_decode) { + /* Optional if you want decode the entire image */ + if (!opj_set_decode_area(l_codec, image, (OPJ_INT32)parameters.DA_x0, + (OPJ_INT32)parameters.DA_y0, (OPJ_INT32)parameters.DA_x1, (OPJ_INT32)parameters.DA_y1)) { + fprintf(stderr, "ERROR -> opj_decompress: failed to set the decoded area\n"); + failed = 1; + goto cleanup; + } - if (!parameters.nb_tile_to_decode) { - /* Optional if you want decode the entire image */ - if (!opj_set_decode_area(l_codec, image, (OPJ_INT32)parameters.DA_x0, - (OPJ_INT32)parameters.DA_y0, (OPJ_INT32)parameters.DA_x1, (OPJ_INT32)parameters.DA_y1)){ - fprintf(stderr, "ERROR -> opj_decompress: failed to set the decoded area\n"); - destroy_parameters(¶meters); - opj_stream_destroy(l_stream); - opj_destroy_codec(l_codec); - opj_image_destroy(image); - return EXIT_FAILURE; + /* Get the decoded image */ + if (!(opj_decode(l_codec, l_stream, image) && opj_end_decompress(l_codec, l_stream))) { + fprintf(stderr, "ERROR -> opj_decompress: failed to decode image!\n"); + failed = 1; + goto cleanup; + } } + else { - /* Get the decoded image */ - if (!(opj_decode(l_codec, l_stream, image) && opj_end_decompress(l_codec, l_stream))) { - fprintf(stderr,"ERROR -> opj_decompress: failed to decode image!\n"); - destroy_parameters(¶meters); - opj_destroy_codec(l_codec); - opj_stream_destroy(l_stream); - opj_image_destroy(image); - return EXIT_FAILURE; + /* It is just here to illustrate how to use the resolution after set parameters */ + /*if (!opj_set_decoded_resolution_factor(l_codec, 5)) { + fprintf(stderr, "ERROR -> opj_decompress: failed to set the resolution factor tile!\n"); + opj_destroy_codec(l_codec); + opj_stream_destroy(l_stream); + opj_image_destroy(image); + return EXIT_FAILURE; + }*/ + + if (!opj_get_decoded_tile(l_codec, l_stream, image, parameters.tile_index)) { + fprintf(stderr, "ERROR -> opj_decompress: failed to decode tile!\n"); + failed = 1; + goto cleanup; + } + fprintf(stdout, "tile %d is decoded!\n\n", parameters.tile_index); } - } - else { - /* It is just here to illustrate how to use the resolution after set parameters */ - /*if (!opj_set_decoded_resolution_factor(l_codec, 5)) { - fprintf(stderr, "ERROR -> opj_decompress: failed to set the resolution factor tile!\n"); - opj_destroy_codec(l_codec); - opj_stream_destroy(l_stream); - opj_image_destroy(image); - return EXIT_FAILURE; - }*/ +#ifdef _OPENMP +#pragma omp atomic +#endif + num_decompressed_images++; - if (!opj_get_decoded_tile(l_codec, l_stream, image, parameters.tile_index)) { - fprintf(stderr, "ERROR -> opj_decompress: failed to decode tile!\n"); - destroy_parameters(¶meters); - opj_destroy_codec(l_codec); - opj_stream_destroy(l_stream); - opj_image_destroy(image); - return EXIT_FAILURE; - } - fprintf(stdout, "tile %d is decoded!\n\n", parameters.tile_index); - } + /* Close the byte stream */ + opj_stream_destroy(l_stream); + l_stream = NULL; + opj_destroy_codec(l_codec); + l_codec = NULL; - tCumulative += opj_clock() - t; - numDecompressedImages++; - /* Close the byte stream */ - opj_stream_destroy(l_stream); - if( image->color_space != OPJ_CLRSPC_SYCC - && image->numcomps == 3 && image->comps[0].dx == image->comps[0].dy - && image->comps[1].dx != 1 ) - image->color_space = OPJ_CLRSPC_SYCC; - else if (image->numcomps <= 2) - image->color_space = OPJ_CLRSPC_GRAY; + if (image->color_space != OPJ_CLRSPC_SYCC + && image->numcomps == 3 && image->comps[0].dx == image->comps[0].dy + && image->comps[1].dx != 1) + image->color_space = OPJ_CLRSPC_SYCC; + else if (image->numcomps <= 2) + image->color_space = OPJ_CLRSPC_GRAY; - if(image->color_space == OPJ_CLRSPC_SYCC){ - color_sycc_to_rgb(image); - } - else if((image->color_space == OPJ_CLRSPC_CMYK) && (parameters.cod_format != TIF_DFMT)){ - color_cmyk_to_rgb(image); - } - else if(image->color_space == OPJ_CLRSPC_EYCC){ - color_esycc_to_rgb(image); - } - - if(image->icc_profile_buf) { + if (image->color_space == OPJ_CLRSPC_SYCC) { + color_sycc_to_rgb(image); + } + else if ((image->color_space == OPJ_CLRSPC_CMYK) && (parameters.cod_format != TIF_DFMT)) { + color_cmyk_to_rgb(image); + } + else if (image->color_space == OPJ_CLRSPC_EYCC) { + color_esycc_to_rgb(image); + } + + if (image->icc_profile_buf) { #if defined(OPJ_HAVE_LIBLCMS1) || defined(OPJ_HAVE_LIBLCMS2) - if(image->icc_profile_len) - color_apply_icc_profile(image); - else - color_cielab_to_rgb(image); + if (image->icc_profile_len) + color_apply_icc_profile(image); + else + color_cielab_to_rgb(image); #endif - free(image->icc_profile_buf); - image->icc_profile_buf = NULL; image->icc_profile_len = 0; - } - - /* Force output precision */ - /* ---------------------- */ - if (parameters.precision != NULL) - { - OPJ_UINT32 compno; - for (compno = 0; compno < image->numcomps; ++compno) + free(image->icc_profile_buf); + image->icc_profile_buf = NULL; image->icc_profile_len = 0; + } + + /* Force output precision */ + /* ---------------------- */ + if (parameters.precision != NULL) { - OPJ_UINT32 precno = compno; - OPJ_UINT32 prec; - - if (precno >= parameters.nb_precision) { - precno = parameters.nb_precision - 1U; - } - - prec = parameters.precision[precno].prec; - if (prec == 0) { - prec = image->comps[compno].prec; - } - - switch (parameters.precision[precno].mode) { + OPJ_UINT32 compno; + for (compno = 0; compno < image->numcomps; ++compno) + { + OPJ_UINT32 precno = compno; + OPJ_UINT32 prec; + + if (precno >= parameters.nb_precision) { + precno = parameters.nb_precision - 1U; + } + + prec = parameters.precision[precno].prec; + if (prec == 0) { + prec = image->comps[compno].prec; + } + + switch (parameters.precision[precno].mode) { case OPJ_PREC_MODE_CLIP: clip_component(&(image->comps[compno]), prec); break; @@ -1420,157 +1436,168 @@ int main(int argc, char **argv) break; default: break; + } + } - - } - } - - /* Upsample components */ - /* ------------------- */ - if (parameters.upsample) - { - image = upsample_image_components(image); - if (image == NULL) { - fprintf(stderr, "ERROR -> opj_decompress: failed to upsample image components!\n"); - destroy_parameters(¶meters); - opj_destroy_codec(l_codec); - return EXIT_FAILURE; - } - } - - /* Force RGB output */ - /* ---------------- */ - if (parameters.force_rgb) - { - switch (image->color_space) { - case OPJ_CLRSPC_SRGB: - break; - case OPJ_CLRSPC_GRAY: - image = convert_gray_to_rgb(image); - break; - default: - fprintf(stderr, "ERROR -> opj_decompress: don't know how to convert image to RGB colorspace!\n"); - opj_image_destroy(image); - image = NULL; - break; - } - if (image == NULL) { - fprintf(stderr, "ERROR -> opj_decompress: failed to convert to RGB image!\n"); - destroy_parameters(¶meters); - opj_destroy_codec(l_codec); - return EXIT_FAILURE; } - } - /* create output image */ - /* ------------------- */ - switch (parameters.cod_format) { - case PXM_DFMT: /* PNM PGM PPM */ - if (imagetopnm(image, parameters.outfile, parameters.split_pnm)) { - fprintf(stderr,"[ERROR] Outfile %s not generated\n",parameters.outfile); - failed = 1; - } - else { - fprintf(stdout,"[INFO] Generated Outfile %s\n",parameters.outfile); + /* Upsample components */ + /* ------------------- */ + if (parameters.upsample) + { + image = upsample_image_components(image); + if (image == NULL) { + fprintf(stderr, "ERROR -> opj_decompress: failed to upsample image components!\n"); + failed = 1; + goto cleanup; + } } - break; - case PGX_DFMT: /* PGX */ - if(imagetopgx(image, parameters.outfile)){ - fprintf(stderr,"[ERROR] Outfile %s not generated\n",parameters.outfile); - failed = 1; - } - else { - fprintf(stdout,"[INFO] Generated Outfile %s\n",parameters.outfile); + /* Force RGB output */ + /* ---------------- */ + if (parameters.force_rgb) + { + switch (image->color_space) { + case OPJ_CLRSPC_SRGB: + break; + case OPJ_CLRSPC_GRAY: + image = convert_gray_to_rgb(image); + break; + default: + fprintf(stderr, "ERROR -> opj_decompress: don't know how to convert image to RGB colorspace!\n"); + opj_image_destroy(image); + image = NULL; + failed = 1; + goto cleanup; + } + if (image == NULL) { + fprintf(stderr, "ERROR -> opj_decompress: failed to convert to RGB image!\n"); + goto cleanup; + } } - break; - case BMP_DFMT: /* BMP */ - if(imagetobmp(image, parameters.outfile)){ - fprintf(stderr,"[ERROR] Outfile %s not generated\n",parameters.outfile); - failed = 1; - } - else { - fprintf(stdout,"[INFO] Generated Outfile %s\n",parameters.outfile); - } - break; + if (store_file_to_disk) { + /* create output image */ + /* ------------------- */ + switch (parameters.cod_format) { + case PXM_DFMT: /* PNM PGM PPM */ + if (imagetopnm(image, outfile, parameters.split_pnm)) { + fprintf(stderr, "[ERROR] Outfile %s not generated\n", outfile); + failed = 1; + } + else { + fprintf(stdout, "[INFO] Generated Outfile %s\n", outfile); + } + break; + + case PGX_DFMT: /* PGX */ + if (imagetopgx(image, outfile)) { + fprintf(stderr, "[ERROR] Outfile %s not generated\n", outfile); + failed = 1; + } + else { + fprintf(stdout, "[INFO] Generated Outfile %s\n", outfile); + } + break; + + case BMP_DFMT: /* BMP */ + if (imagetobmp(image, outfile)) { + fprintf(stderr, "[ERROR] Outfile %s not generated\n", outfile); + failed = 1; + } + else { + fprintf(stdout, "[INFO] Generated Outfile %s\n", outfile); + } + break; #ifdef OPJ_HAVE_LIBTIFF - case TIF_DFMT: /* TIFF */ - if(imagetotif(image, parameters.outfile)){ - fprintf(stderr,"[ERROR] Outfile %s not generated\n",parameters.outfile); - failed = 1; - } - else { - fprintf(stdout,"[INFO] Generated Outfile %s\n",parameters.outfile); - } - break; + case TIF_DFMT: /* TIFF */ + if (imagetotif(image, outfile)) { + fprintf(stderr, "[ERROR] Outfile %s not generated\n", outfile); + failed = 1; + } + else { + fprintf(stdout, "[INFO] Generated Outfile %s\n", outfile); + } + break; #endif /* OPJ_HAVE_LIBTIFF */ - case RAW_DFMT: /* RAW */ - if(imagetoraw(image, parameters.outfile)){ - fprintf(stderr,"[ERROR] Error generating raw file. Outfile %s not generated\n",parameters.outfile); - failed = 1; - } - else { - fprintf(stdout,"[INFO] Generated Outfile %s\n",parameters.outfile); - } - break; + case RAW_DFMT: /* RAW */ + if (imagetoraw(image, outfile)) { + fprintf(stderr, "[ERROR] Error generating raw file. Outfile %s not generated\n", outfile); + failed = 1; + } + else { + fprintf(stdout, "[INFO] Generated Outfile %s\n", outfile); + } + break; - case RAWL_DFMT: /* RAWL */ - if(imagetorawl(image, parameters.outfile)){ - fprintf(stderr,"[ERROR] Error generating rawl file. Outfile %s not generated\n",parameters.outfile); - failed = 1; - } - else { - fprintf(stdout,"[INFO] Generated Outfile %s\n",parameters.outfile); - } - break; + case RAWL_DFMT: /* RAWL */ + if (imagetorawl(image, outfile)) { + fprintf(stderr, "[ERROR] Error generating rawl file. Outfile %s not generated\n", outfile); + failed = 1; + } + else { + fprintf(stdout, "[INFO] Generated Outfile %s\n", outfile); + } + break; - case TGA_DFMT: /* TGA */ - if(imagetotga(image, parameters.outfile)){ - fprintf(stderr,"[ERROR] Error generating tga file. Outfile %s not generated\n",parameters.outfile); - failed = 1; - } - else { - fprintf(stdout,"[INFO] Generated Outfile %s\n",parameters.outfile); - } - break; + case TGA_DFMT: /* TGA */ + if (imagetotga(image, outfile)) { + fprintf(stderr, "[ERROR] Error generating tga file. Outfile %s not generated\n", outfile); + failed = 1; + } + else { + fprintf(stdout, "[INFO] Generated Outfile %s\n", outfile); + } + break; #ifdef OPJ_HAVE_LIBPNG - case PNG_DFMT: /* PNG */ - if(imagetopng(image, parameters.outfile)){ - fprintf(stderr,"[ERROR] Error generating png file. Outfile %s not generated\n",parameters.outfile); - failed = 1; - } - else { - fprintf(stdout,"[INFO] Generated Outfile %s\n",parameters.outfile); - } - break; + case PNG_DFMT: /* PNG */ + if (imagetopng(image, outfile)) { + fprintf(stderr, "[ERROR] Error generating png file. Outfile %s not generated\n", outfile); + failed = 1; + } + else { + fprintf(stdout, "[INFO] Generated Outfile %s\n", outfile); + } + break; #endif /* OPJ_HAVE_LIBPNG */ -/* Can happen if output file is TIFF or PNG - * and OPJ_HAVE_LIBTIF or OPJ_HAVE_LIBPNG is undefined -*/ - default: - fprintf(stderr,"[ERROR] Outfile %s not generated\n",parameters.outfile); - failed = 1; - } + /* Can happen if output file is TIFF or PNG + * and OPJ_HAVE_LIBTIF or OPJ_HAVE_LIBPNG is undefined + */ + default: + fprintf(stderr, "[ERROR] Outfile %s not generated\n", outfile); + failed = 1; + break; + } - /* free remaining structures */ - if (l_codec) { - opj_destroy_codec(l_codec); - } + } + /* free remaining structures */ +cleanup: + if (l_stream) + opj_stream_destroy(l_stream); + if (l_codec) + opj_destroy_codec(l_codec); + if (image) + opj_image_destroy(image); - /* free image data structure */ - opj_image_destroy(image); + /* destroy the codestream index */ + opj_destroy_cstr_index(&cstr_index); - /* destroy the codestream index */ - opj_destroy_cstr_index(&cstr_index); + if (failed) + (void)remove(outfile); /* ignore return value */ + } - if(failed) (void)remove(parameters.outfile); /* ignore return value */ +#ifdef _OPENMP } +#endif + + t_cumulative = opj_clock() - t_cumulative; destroy_parameters(¶meters); - if (numDecompressedImages) { - fprintf(stdout, "decode time: %d ms\n", (int)( (tCumulative * 1000.0) / (OPJ_FLOAT64)numDecompressedImages)); + + if (num_decompressed_images) { + fprintf(stdout, "decode time: %d ms \n", (int)( (t_cumulative * 1000) / num_decompressed_images)); } + getchar(); return failed ? EXIT_FAILURE : EXIT_SUCCESS; } /*end main*/ diff --git a/src/lib/openjp2/CMakeLists.txt b/src/lib/openjp2/CMakeLists.txt index 500e905c4..42aef4256 100644 --- a/src/lib/openjp2/CMakeLists.txt +++ b/src/lib/openjp2/CMakeLists.txt @@ -1,5 +1,15 @@ include_regular_expression("^.*$") +if (BUILD_WITH_OPENMP) +find_package(OpenMP) +if (OPENMP_FOUND) + add_definitions(-DOPJ_NUM_CORES=8) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") +endif() +endif() + + # install( FILES ${CMAKE_CURRENT_BINARY_DIR}/opj_config.h DESTINATION ${OPENJPEG_INSTALL_INCLUDE_DIR} COMPONENT Headers) @@ -37,8 +47,12 @@ set(OPENJPEG_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/pi.h ${CMAKE_CURRENT_SOURCE_DIR}/raw.c ${CMAKE_CURRENT_SOURCE_DIR}/raw.h - ${CMAKE_CURRENT_SOURCE_DIR}/t1.c + ${CMAKE_CURRENT_SOURCE_DIR}/segmented_stream.c + ${CMAKE_CURRENT_SOURCE_DIR}/segmented_stream.h + ${CMAKE_CURRENT_SOURCE_DIR}/t1.c ${CMAKE_CURRENT_SOURCE_DIR}/t1.h + ${CMAKE_CURRENT_SOURCE_DIR}/t1_opt.c + ${CMAKE_CURRENT_SOURCE_DIR}/t1_opt.h ${CMAKE_CURRENT_SOURCE_DIR}/t2.c ${CMAKE_CURRENT_SOURCE_DIR}/t2.h ${CMAKE_CURRENT_SOURCE_DIR}/tcd.c @@ -53,6 +67,8 @@ set(OPENJPEG_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/opj_malloc.c ${CMAKE_CURRENT_SOURCE_DIR}/opj_malloc.h ${CMAKE_CURRENT_SOURCE_DIR}/opj_stdint.h + ${CMAKE_CURRENT_SOURCE_DIR}/vector.h + ${CMAKE_CURRENT_SOURCE_DIR}/vector.c ) if(BUILD_JPIP) add_definitions(-DUSE_JPIP) diff --git a/src/lib/openjp2/bio.c b/src/lib/openjp2/bio.c index e4edb3724..09a9cddaf 100644 --- a/src/lib/openjp2/bio.c +++ b/src/lib/openjp2/bio.c @@ -48,7 +48,7 @@ Write a bit @param bio BIO handle @param b Bit to write (0 or 1) */ -static void opj_bio_putbit(opj_bio_t *bio, OPJ_UINT32 b); +static void opj_bio_putbit(opj_bio_t *bio, OPJ_BYTE b); /** Read a bit @param bio BIO handle @@ -79,31 +79,32 @@ static OPJ_BOOL opj_bio_bytein(opj_bio_t *bio); */ static OPJ_BOOL opj_bio_byteout(opj_bio_t *bio) { - bio->buf = (bio->buf << 8) & 0xffff; - bio->ct = bio->buf == 0xff00 ? 7 : 8; + bio->ct = bio->buf == 0xff ? 7 : 8; if ((OPJ_SIZE_T)bio->bp >= (OPJ_SIZE_T)bio->end) { return OPJ_FALSE; } - *bio->bp++ = (OPJ_BYTE)(bio->buf >> 8); + if (!bio->simOut) + *bio->bp = bio->buf; + bio->bp++; + bio->buf = 0; return OPJ_TRUE; } static OPJ_BOOL opj_bio_bytein(opj_bio_t *bio) { - bio->buf = (bio->buf << 8) & 0xffff; - bio->ct = bio->buf == 0xff00 ? 7 : 8; + bio->ct = bio->buf == 0xff ? 7 : 8; if ((OPJ_SIZE_T)bio->bp >= (OPJ_SIZE_T)bio->end) { return OPJ_FALSE; } - bio->buf |= *bio->bp++; + bio->buf = *bio->bp++; return OPJ_TRUE; } -static void opj_bio_putbit(opj_bio_t *bio, OPJ_UINT32 b) { +static void opj_bio_putbit(opj_bio_t *bio, OPJ_BYTE b) { if (bio->ct == 0) { opj_bio_byteout(bio); /* MSD: why not check the return value of this function ? */ } bio->ct--; - bio->buf |= b << bio->ct; + bio->buf |= (OPJ_BYTE)(b << bio->ct); } static OPJ_UINT32 opj_bio_getbit(opj_bio_t *bio) { @@ -141,6 +142,7 @@ void opj_bio_init_enc(opj_bio_t *bio, OPJ_BYTE *bp, OPJ_UINT32 len) { bio->bp = bp; bio->buf = 0; bio->ct = 8; + bio->simOut = OPJ_FALSE; } void opj_bio_init_dec(opj_bio_t *bio, OPJ_BYTE *bp, OPJ_UINT32 len) { diff --git a/src/lib/openjp2/bio.h b/src/lib/openjp2/bio.h index fba242847..74440c790 100644 --- a/src/lib/openjp2/bio.h +++ b/src/lib/openjp2/bio.h @@ -61,9 +61,11 @@ typedef struct opj_bio { /** pointer to the present position in the buffer */ OPJ_BYTE *bp; /** temporary place where each byte is read or written */ - OPJ_UINT32 buf; + OPJ_BYTE buf; /** coder : number of bits free to write. decoder : number of bits read */ - OPJ_UINT32 ct; + OPJ_BYTE ct; + + OPJ_BOOL simOut; } opj_bio_t; /** @name Exported functions */ diff --git a/src/lib/openjp2/cio.c b/src/lib/openjp2/cio.c index b115cf529..678e6bc42 100644 --- a/src/lib/openjp2/cio.c +++ b/src/lib/openjp2/cio.c @@ -156,15 +156,16 @@ opj_stream_t* OPJ_CALLCONV opj_stream_create(OPJ_SIZE_T p_buffer_size,OPJ_BOOL l return 00; } - l_stream->m_buffer_size = p_buffer_size; - l_stream->m_stored_data = (OPJ_BYTE *) opj_malloc(p_buffer_size); - if (! l_stream->m_stored_data) { - opj_free(l_stream); - return 00; + if (p_buffer_size) { + l_stream->m_buffer_size = p_buffer_size; + l_stream->m_stored_data = (OPJ_BYTE *)opj_malloc(p_buffer_size); + if (!l_stream->m_stored_data) { + opj_free(l_stream); + return 00; + } + l_stream->m_current_data = l_stream->m_stored_data; } - l_stream->m_current_data = l_stream->m_stored_data; - if (l_is_input) { l_stream->m_status |= OPJ_STREAM_STATUS_INPUT; l_stream->m_opj_skip = opj_stream_read_skip; @@ -197,8 +198,10 @@ void OPJ_CALLCONV opj_stream_destroy(opj_stream_t* p_stream) if (l_stream->m_free_user_data_fn) { l_stream->m_free_user_data_fn(l_stream->m_user_data); } - opj_free(l_stream->m_stored_data); - l_stream->m_stored_data = 00; + if (l_stream->m_stored_data) { + opj_free(l_stream->m_stored_data); + l_stream->m_stored_data = 00; + } opj_free(l_stream); } } @@ -214,6 +217,17 @@ void OPJ_CALLCONV opj_stream_set_read_function(opj_stream_t* p_stream, opj_strea l_stream->m_read_fn = p_function; } +void OPJ_CALLCONV opj_stream_set_zero_copy_read_function(opj_stream_t* p_stream, opj_stream_zero_copy_read_fn p_function) +{ + opj_stream_private_t* l_stream = (opj_stream_private_t*)p_stream; + + if ((!l_stream) || (!(l_stream->m_status & OPJ_STREAM_STATUS_INPUT))) { + return; + } + + l_stream->m_zero_copy_read_fn = p_function; +} + void OPJ_CALLCONV opj_stream_set_seek_function(opj_stream_t* p_stream, opj_stream_seek_fn p_function) { opj_stream_private_t* l_stream = (opj_stream_private_t*) p_stream; @@ -263,6 +277,12 @@ void OPJ_CALLCONV opj_stream_set_user_data_length(opj_stream_t* p_stream, OPJ_UI l_stream->m_user_data_length = data_length; } + + +OPJ_BOOL opj_stream_supports_zero_copy_read(opj_stream_private_t * p_stream) { + return p_stream->m_zero_copy_read_fn ? OPJ_TRUE : OPJ_FALSE; +} + OPJ_SIZE_T opj_stream_read_data (opj_stream_private_t * p_stream,OPJ_BYTE * p_buffer, OPJ_SIZE_T p_size, opj_event_mgr_t * p_event_mgr) { OPJ_SIZE_T l_read_nb_bytes = 0; @@ -370,6 +390,26 @@ OPJ_SIZE_T opj_stream_read_data (opj_stream_private_t * p_stream,OPJ_BYTE * p_bu } } + + +OPJ_SIZE_T opj_stream_read_data_zero_copy(opj_stream_private_t * p_stream, OPJ_BYTE ** p_buffer, OPJ_SIZE_T p_size, opj_event_mgr_t * p_event_mgr) +{ + OPJ_SIZE_T l_read_nb_bytes = p_stream->m_zero_copy_read_fn((void**)p_buffer, p_size, p_stream->m_user_data); + + if (l_read_nb_bytes == (OPJ_SIZE_T)-1) { + /* end of stream */ + opj_event_msg(p_event_mgr, EVT_INFO, "Stream reached its end !\n"); + p_stream->m_status |= OPJ_STREAM_STATUS_END; + return (OPJ_SIZE_T)-1; + } + else { + p_stream->m_byte_offset += (OPJ_OFF_T)l_read_nb_bytes; + return l_read_nb_bytes; + } + +} + + OPJ_SIZE_T opj_stream_write_data (opj_stream_private_t * p_stream, const OPJ_BYTE * p_buffer, OPJ_SIZE_T p_size, diff --git a/src/lib/openjp2/cio.h b/src/lib/openjp2/cio.h index 4ea03ff34..0721e0cda 100644 --- a/src/lib/openjp2/cio.h +++ b/src/lib/openjp2/cio.h @@ -98,10 +98,16 @@ typedef struct opj_stream_private OPJ_UINT64 m_user_data_length; /** - * Pointer to actual read function (NULL at the initialization of the cio. + * Pointer to actual read function (NULL at the initialization of the cio). */ opj_stream_read_fn m_read_fn; + /** + * Pointer to actual zero copy read function (NULL at the initialization of the cio). + */ + opj_stream_zero_copy_read_fn m_zero_copy_read_fn; + + /** * Pointer to actual write function (NULL at the initialization of the cio. */ @@ -268,6 +274,13 @@ void opj_write_float_BE(OPJ_BYTE * p_buffer, OPJ_FLOAT32 p_value); */ OPJ_SIZE_T opj_stream_read_data (opj_stream_private_t * p_stream,OPJ_BYTE * p_buffer, OPJ_SIZE_T p_size, struct opj_event_mgr * p_event_mgr); +OPJ_SIZE_T opj_stream_read_data_zero_copy(opj_stream_private_t * p_stream, OPJ_BYTE ** p_buffer, OPJ_SIZE_T p_size, struct opj_event_mgr * p_event_mgr); + +/** +* Check if this stream supports zero copy reads +*/ +OPJ_BOOL opj_stream_supports_zero_copy_read(opj_stream_private_t * p_stream); + /** * Writes some bytes to the stream. * @param p_stream the stream to write data to. diff --git a/src/lib/openjp2/image.c b/src/lib/openjp2/image.c index 23462f05f..3ba8139e4 100644 --- a/src/lib/openjp2/image.c +++ b/src/lib/openjp2/image.c @@ -64,8 +64,7 @@ opj_image_t* OPJ_CALLCONV opj_image_create(OPJ_UINT32 numcmpts, opj_image_cmptpa comp->prec = cmptparms[compno].prec; comp->bpp = cmptparms[compno].bpp; comp->sgnd = cmptparms[compno].sgnd; - comp->data = (OPJ_INT32*) opj_calloc(comp->w * comp->h, sizeof(OPJ_INT32)); - if(!comp->data) { + if(!opj_image_single_component_data_alloc(comp)) { /* TODO replace with event manager, breaks API */ /* fprintf(stderr,"Unable to allocate memory for image.\n"); */ opj_image_destroy(image); @@ -80,15 +79,7 @@ opj_image_t* OPJ_CALLCONV opj_image_create(OPJ_UINT32 numcmpts, opj_image_cmptpa void OPJ_CALLCONV opj_image_destroy(opj_image_t *image) { if(image) { if(image->comps) { - OPJ_UINT32 compno; - - /* image components */ - for(compno = 0; compno < image->numcomps; compno++) { - opj_image_comp_t *image_comp = &(image->comps[compno]); - if(image_comp->data) { - opj_free(image_comp->data); - } - } + opj_image_all_components_data_free(image); opj_free(image->comps); } @@ -159,12 +150,7 @@ void opj_copy_image_header(const opj_image_t* p_image_src, opj_image_t* p_image_ p_image_dest->y1 = p_image_src->y1; if (p_image_dest->comps){ - for(compno = 0; compno < p_image_dest->numcomps; compno++) { - opj_image_comp_t *image_comp = &(p_image_dest->comps[compno]); - if(image_comp->data) { - opj_free(image_comp->data); - } - } + opj_image_all_components_data_free(p_image_dest); opj_free(p_image_dest->comps); p_image_dest->comps = NULL; } diff --git a/src/lib/openjp2/j2k.c b/src/lib/openjp2/j2k.c index f0e565eae..67c7af478 100644 --- a/src/lib/openjp2/j2k.c +++ b/src/lib/openjp2/j2k.c @@ -48,6 +48,25 @@ /** @name Local static functions */ /*@{*/ +/** +Transfer data from src to dest for each component, and null out src data. +Assumption: src and dest have the same number of components +*/ +static void opj_j2k_transfer_image_data(opj_image_t* src, opj_image_t* dest) { + OPJ_UINT32 compno; + if (!src || !dest || !src->comps || !dest->comps || src->numcomps != dest->numcomps) + return; + + for (compno = 0; compno < src->numcomps; compno++) { + opj_image_comp_t* src_comp = src->comps + compno; + opj_image_comp_t* dest_comp = dest->comps + compno; + dest_comp->resno_decoded = src_comp->resno_decoded; + opj_image_single_component_data_free(dest_comp); + dest_comp->data = src_comp->data; + src_comp->data = NULL; + } +} + /** * Sets up the procedures to do on reading header. Developpers wanting to extend the library can add their own reading procedures. */ @@ -2445,7 +2464,7 @@ static OPJ_BOOL opj_j2k_write_cod( opj_j2k_t *p_j2k, 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) */ + opj_write_bytes(l_current_data,(OPJ_UINT32)l_tcp->prg,1); /* SGcod (A) */ ++l_current_data; opj_write_bytes(l_current_data,l_tcp->numlayers,2); /* SGcod (B) */ @@ -3165,7 +3184,7 @@ static void opj_j2k_write_poc_in_memory( opj_j2k_t *p_j2k, 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 */ + opj_write_bytes(l_current_data,(OPJ_UINT32)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*/ @@ -4363,9 +4382,7 @@ static OPJ_BOOL opj_j2k_read_sod (opj_j2k_t *p_j2k, { OPJ_SIZE_T l_current_read_size; opj_codestream_index_t * l_cstr_index = 00; - OPJ_BYTE ** l_current_data = 00; opj_tcp_t * l_tcp = 00; - OPJ_UINT32 * l_tile_len = 00; OPJ_BOOL l_sot_length_pb_detected = OPJ_FALSE; /* preconditions */ @@ -4391,8 +4408,6 @@ static OPJ_BOOL opj_j2k_read_sod (opj_j2k_t *p_j2k, } } - l_current_data = &(l_tcp->m_data); - l_tile_len = &l_tcp->m_data_size; /* Patch to support new PHR data */ if (p_j2k->m_specific_param.m_decoder.m_sot_length) { @@ -4402,28 +4417,6 @@ static OPJ_BOOL opj_j2k_read_sod (opj_j2k_t *p_j2k, opj_event_msg(p_manager, EVT_ERROR, "Tile part length size inconsistent with stream length\n"); return OPJ_FALSE; } - if (! *l_current_data) { - /* LH: oddly enough, in this path, l_tile_len!=0. - * TODO: If this was consistent, we could simplify the code to only use realloc(), as realloc(0,...) default to malloc(0,...). - */ - *l_current_data = (OPJ_BYTE*) opj_malloc(p_j2k->m_specific_param.m_decoder.m_sot_length); - } - else { - OPJ_BYTE *l_new_current_data = (OPJ_BYTE *) opj_realloc(*l_current_data, *l_tile_len + p_j2k->m_specific_param.m_decoder.m_sot_length); - if (! l_new_current_data) { - opj_free(*l_current_data); - /*nothing more is done as l_current_data will be set to null, and just - afterward we enter in the error path - and the actual tile_len is updated (committed) at the end of the - function. */ - } - *l_current_data = l_new_current_data; - } - - if (*l_current_data == 00) { - opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to decode tile\n"); - return OPJ_FALSE; - } } else { l_sot_length_pb_detected = OPJ_TRUE; @@ -4454,11 +4447,24 @@ static OPJ_BOOL opj_j2k_read_sod (opj_j2k_t *p_j2k, /* Patch to support new PHR data */ if (!l_sot_length_pb_detected) { - l_current_read_size = opj_stream_read_data( - p_stream, - *l_current_data + *l_tile_len, - p_j2k->m_specific_param.m_decoder.m_sot_length, - p_manager); + if (opj_stream_supports_zero_copy_read(p_stream)) { + OPJ_BYTE* ptr = NULL; + l_current_read_size = opj_stream_read_data_zero_copy(p_stream, + &ptr, + p_j2k->m_specific_param.m_decoder.m_sot_length, + p_manager); + opj_seg_buf_push_back(&l_tcp->m_data, ptr, p_j2k->m_specific_param.m_decoder.m_sot_length); + + } + else { + opj_seg_buf_alloc_and_push_back(&l_tcp->m_data, p_j2k->m_specific_param.m_decoder.m_sot_length); + l_current_read_size = opj_stream_read_data( + p_stream, + opj_seg_buf_get_global_ptr(&l_tcp->m_data), + p_j2k->m_specific_param.m_decoder.m_sot_length, + p_manager); + + } } else { @@ -4471,9 +4477,6 @@ static OPJ_BOOL opj_j2k_read_sod (opj_j2k_t *p_j2k, else { p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_TPHSOT; } - - *l_tile_len += (OPJ_UINT32)l_current_read_size; - return OPJ_TRUE; } @@ -5362,7 +5365,7 @@ static OPJ_BOOL opj_j2k_write_mcc_record( opj_j2k_t *p_j2k, l_current_data+=l_nb_bytes_for_comp; } - l_tmcc = ((!p_mcc_record->m_is_irreversible)&1)<<16; + l_tmcc = ((OPJ_UINT32)((!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; @@ -7673,11 +7676,7 @@ static void opj_j2k_tcp_destroy (opj_tcp_t *p_tcp) static void opj_j2k_tcp_data_destroy (opj_tcp_t *p_tcp) { - if (p_tcp->m_data) { - opj_free(p_tcp->m_data); - p_tcp->m_data = NULL; - p_tcp->m_data_size = 0; - } + opj_seg_buf_cleanup(&p_tcp->m_data); } static void opj_j2k_cp_destroy (opj_cp_t *p_cp) @@ -8057,7 +8056,7 @@ OPJ_BOOL opj_j2k_read_tile_header( opj_j2k_t * p_j2k, OPJ_UINT32 l_nb_tiles = p_j2k->m_cp.th * p_j2k->m_cp.tw; l_tcp = p_j2k->m_cp.tcps + p_j2k->m_current_tile_number; - while( (p_j2k->m_current_tile_number < l_nb_tiles) && (l_tcp->m_data == 00) ) { + while( (p_j2k->m_current_tile_number < l_nb_tiles) && (l_tcp->m_data.segments.data == 00) ) { ++p_j2k->m_current_tile_number; ++l_tcp; } @@ -8117,26 +8116,62 @@ OPJ_BOOL opj_j2k_decode_tile ( opj_j2k_t * p_j2k, } l_tcp = &(p_j2k->m_cp.tcps[p_tile_index]); - if (! l_tcp->m_data) { + if (! l_tcp->m_data.segments.data) { opj_j2k_tcp_destroy(l_tcp); return OPJ_FALSE; } - if (! opj_tcd_decode_tile( p_j2k->m_tcd, - l_tcp->m_data, - l_tcp->m_data_size, - p_tile_index, - p_j2k->cstr_index, p_manager) ) { + if (! opj_tcd_decode_tile( p_j2k->m_tcd, + &l_tcp->m_data, + p_tile_index, + p_j2k->cstr_index, p_manager) ) { opj_j2k_tcp_destroy(l_tcp); p_j2k->m_specific_param.m_decoder.m_state |= 0x8000;/*FIXME J2K_DEC_STATE_ERR;*/ opj_event_msg(p_manager, EVT_ERROR, "Failed to decode.\n"); return OPJ_FALSE; } - if (! opj_tcd_update_tile_data(p_j2k->m_tcd,p_data,p_data_size)) { - return OPJ_FALSE; - } + /* if p_data is not null, then copy decoded resolutions from tile data into p_data. + Otherwise, simply copy tile data pointer to output image + */ + if (p_data) { + if (!opj_tcd_update_tile_data(p_j2k->m_tcd, p_data, p_data_size)) { + return OPJ_FALSE; + } + } + else { + /* transfer data from tile component to output image */ + OPJ_UINT32 compno = 0; + for (compno = 0; compno < p_j2k->m_output_image->numcomps; compno++) { + OPJ_UINT32 l_size_comp = 0; + OPJ_UINT32 i, j; + opj_tcd_tilecomp_t* tilec = p_j2k->m_tcd->tcd_image->tiles->comps + compno; + opj_image_comp_t* comp = p_j2k->m_output_image->comps + compno; + comp->data = tilec->data; + tilec->data = NULL; + comp->resno_decoded = p_j2k->m_tcd->image->comps[compno].resno_decoded; + + /* now sanitize data (signed data is broken at the moment */ + l_size_comp = (comp->prec + 7) >> 3; + if (l_size_comp <= 2) { + for (j = 0; j < comp->h; ++j) + for (i = 0; i < comp->w; ++i) { + if (l_size_comp == 1) + comp->data[i + j*comp->w] = + comp->sgnd ? comp->data[i + j*comp->w] : + comp->data[i + j*comp->w] & 0xFF; + else + comp->data[i + j*comp->w] = + comp->sgnd ? comp->data[i + j*comp->w] : + comp->data[i + j*comp->w] & 0xFFFF; + + } + } + + } + } + /* To avoid to destroy the tcp which can be useful when we try to decode a tile decoded before (cf j2k_random_tile_access) * we destroy just the data which will be re-read in read_tile_header*/ /*opj_j2k_tcp_destroy(l_tcp); @@ -8178,6 +8213,12 @@ OPJ_BOOL opj_j2k_decode_tile ( opj_j2k_t * p_j2k, return OPJ_TRUE; } +/* +p_data stores the number of resolutions decoded, in the actual precision of the decoded image. + +This method copies a sub-region of this region into p_output_image (which stores data in 32 bit precision) + +*/ static OPJ_BOOL opj_j2k_update_image_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data, opj_image_t* p_output_image) { OPJ_UINT32 i,j,k = 0; @@ -8194,7 +8235,7 @@ static OPJ_BOOL opj_j2k_update_image_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data, opj_tcd_tilecomp_t * l_tilec = 00; opj_image_t * l_image_src = 00; - OPJ_UINT32 l_size_comp, l_remaining; + OPJ_UINT32 l_size_comp; OPJ_INT32 * l_dest_ptr; opj_tcd_resolution_t* l_res= 00; @@ -8208,9 +8249,7 @@ static OPJ_BOOL opj_j2k_update_image_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data, /* Allocate output component buffer if necessary */ if (!l_img_comp_dest->data) { - - l_img_comp_dest->data = (OPJ_INT32*) opj_calloc((OPJ_SIZE_T)l_img_comp_dest->w * (OPJ_SIZE_T)l_img_comp_dest->h, sizeof(OPJ_INT32)); - if (! l_img_comp_dest->data) { + if (!opj_image_single_component_data_alloc(l_img_comp_dest)) { return OPJ_FALSE; } } @@ -8220,14 +8259,9 @@ static OPJ_BOOL opj_j2k_update_image_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data, /*-----*/ /* Compute the precision of the output buffer */ - l_size_comp = l_img_comp_src->prec >> 3; /*(/ 8)*/ - l_remaining = l_img_comp_src->prec & 7; /* (%8) */ + l_size_comp = (l_img_comp_src->prec + 7) >> 3; l_res = l_tilec->resolutions + l_img_comp_src->resno_decoded; - if (l_remaining) { - ++l_size_comp; - } - if (l_size_comp == 3) { l_size_comp = 4; } @@ -9694,24 +9728,82 @@ static OPJ_BOOL opj_j2k_allocate_tile_element_cstr_index(opj_j2k_t *p_j2k) return OPJ_TRUE; } +static OPJ_BOOL opj_j2k_needs_copy_tile_data(opj_j2k_t *p_j2k) { + return OPJ_TRUE; +#if 0 + /* single tile, RGB images only*/ + OPJ_BOOL copy_tile_data = (p_j2k->m_cp.th * p_j2k->m_cp.tw > 1) || + p_j2k->m_output_image->numcomps != 3 || + p_j2k->m_output_image->numcomps != 3 || + p_j2k->m_tcd->tcd_image->tiles->numcomps != 3; + + OPJ_UINT32 i = 0; + + + + /* If we only have one tile, check the following: + + 1) Check if each output image component's dimensions match + destination image component dimensions. It they don't, then set copy_tile_data to OPJ_TRUE + and break. + + 2) Check if we are not decoding all resolutions. If we are not, set copy_tile_data to OPJ_TRUE + and break; + + */ + if (!copy_tile_data) { + + for (i = 0; i < p_j2k->m_output_image->numcomps; i++) { + opj_tcd_tilecomp_t* tilec = p_j2k->m_tcd->tcd_image->tiles->comps + i; + opj_image_comp_t* dest_comp = p_j2k->m_output_image->comps + i; + OPJ_UINT32 l_x0_dest = opj_uint_ceildivpow2(dest_comp->x0, dest_comp->factor); + OPJ_UINT32 l_y0_dest = opj_uint_ceildivpow2(dest_comp->y0, dest_comp->factor); + OPJ_UINT32 l_x1_dest = l_x0_dest + dest_comp->w; /* can't overflow given that image->x1 is uint32 */ + OPJ_UINT32 l_y1_dest = l_y0_dest + dest_comp->h; + + opj_image_comp_t* src_comp = p_j2k->m_tcd->image->comps + i; + + if (src_comp->sgnd) { + copy_tile_data = OPJ_TRUE; + break; + } + if (src_comp->x0 != l_x0_dest || + src_comp->y0 != l_y0_dest || + src_comp->w != (l_x1_dest - l_x0_dest) || + src_comp->h != (l_y1_dest - l_y0_dest)) { + copy_tile_data = OPJ_TRUE; + break; + } + if (src_comp->resno_decoded < tilec->numresolutions) { + copy_tile_data = OPJ_TRUE; + break; + } + } + } + return copy_tile_data; +#endif +} + static OPJ_BOOL opj_j2k_decode_tiles ( opj_j2k_t *p_j2k, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager) { OPJ_BOOL l_go_on = OPJ_TRUE; OPJ_UINT32 l_current_tile_no; - OPJ_UINT32 l_data_size,l_max_data_size; + OPJ_UINT32 l_data_size=0,l_max_data_size=0; OPJ_INT32 l_tile_x0,l_tile_y0,l_tile_x1,l_tile_y1; OPJ_UINT32 l_nb_comps; - OPJ_BYTE * l_current_data; + OPJ_BYTE * l_current_data=NULL; OPJ_UINT32 nr_tiles = 0; - - l_current_data = (OPJ_BYTE*)opj_malloc(1000); - if (! l_current_data) { - opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to decode tiles\n"); - return OPJ_FALSE; - } - l_max_data_size = 1000; + + if (opj_j2k_needs_copy_tile_data(p_j2k)) { + l_current_data = (OPJ_BYTE*)opj_malloc(1); + if (!l_current_data) { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to decode tiles\n"); + return OPJ_FALSE; + } + l_max_data_size = 1; + } for (;;) { if (! opj_j2k_read_tile_header( p_j2k, @@ -9723,38 +9815,44 @@ static OPJ_BOOL opj_j2k_decode_tiles ( opj_j2k_t *p_j2k, &l_go_on, p_stream, p_manager)) { - opj_free(l_current_data); + if (l_current_data) + opj_free(l_current_data); return OPJ_FALSE; } if (! l_go_on) { break; } - - if (l_data_size > l_max_data_size) { + + if (l_current_data && (l_data_size > l_max_data_size)) { OPJ_BYTE *l_new_current_data = (OPJ_BYTE *) opj_realloc(l_current_data, l_data_size); if (! l_new_current_data) { - opj_free(l_current_data); + opj_free(l_current_data); opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to decode tile %d/%d\n", l_current_tile_no +1, p_j2k->m_cp.th * p_j2k->m_cp.tw); return OPJ_FALSE; } l_current_data = l_new_current_data; l_max_data_size = l_data_size; } + if (! opj_j2k_decode_tile(p_j2k,l_current_tile_no,l_current_data,l_data_size,p_stream,p_manager)) { - opj_free(l_current_data); + if (l_current_data) + opj_free(l_current_data); opj_event_msg(p_manager, EVT_ERROR, "Failed to decode tile %d/%d\n", l_current_tile_no +1, p_j2k->m_cp.th * p_j2k->m_cp.tw); return OPJ_FALSE; } opj_event_msg(p_manager, EVT_INFO, "Tile %d/%d has been decoded.\n", l_current_tile_no +1, p_j2k->m_cp.th * p_j2k->m_cp.tw); + + /* copy from current data to output image, if necessary */ + if (l_current_data) { + if (!opj_j2k_update_image_data(p_j2k->m_tcd, l_current_data, p_j2k->m_output_image)) { + opj_free(l_current_data); + return OPJ_FALSE; + } + opj_event_msg(p_manager, EVT_INFO, "Image data has been updated with tile %d.\n\n", l_current_tile_no + 1); + } - if (! opj_j2k_update_image_data(p_j2k->m_tcd,l_current_data, p_j2k->m_output_image)) { - opj_free(l_current_data); - return OPJ_FALSE; - } - opj_event_msg(p_manager, EVT_INFO, "Image data has been updated with tile %d.\n\n", l_current_tile_no + 1); - if(opj_stream_get_number_byte_left(p_stream) == 0 && p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_NEOC) break; @@ -9762,7 +9860,8 @@ static OPJ_BOOL opj_j2k_decode_tiles ( opj_j2k_t *p_j2k, break; } - opj_free(l_current_data); + if (l_current_data) + opj_free(l_current_data); return OPJ_TRUE; } @@ -9794,24 +9893,27 @@ static OPJ_BOOL opj_j2k_decode_one_tile ( opj_j2k_t *p_j2k, OPJ_BOOL l_go_on = OPJ_TRUE; OPJ_UINT32 l_current_tile_no; OPJ_UINT32 l_tile_no_to_dec; - OPJ_UINT32 l_data_size,l_max_data_size; + OPJ_UINT32 l_data_size=0,l_max_data_size=0; OPJ_INT32 l_tile_x0,l_tile_y0,l_tile_x1,l_tile_y1; OPJ_UINT32 l_nb_comps; - OPJ_BYTE * l_current_data; + OPJ_BYTE * l_current_data=NULL; - l_current_data = (OPJ_BYTE*)opj_malloc(1000); - if (! l_current_data) { - opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to decode one tile\n"); - return OPJ_FALSE; - } - l_max_data_size = 1000; + if (opj_j2k_needs_copy_tile_data(p_j2k)) { + l_current_data = (OPJ_BYTE*)opj_malloc(1); + if (!l_current_data) { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to decode tiles\n"); + return OPJ_FALSE; + } + l_max_data_size = 1; + } /*Allocate and initialize some elements of codestrem index if not already done*/ if( !p_j2k->cstr_index->tile_index) { if (!opj_j2k_allocate_tile_element_cstr_index(p_j2k)){ - opj_free(l_current_data); - return OPJ_FALSE; + if (l_current_data) + opj_free(l_current_data); + return OPJ_FALSE; } } /* Move into the codestream to the first SOT used to decode the desired tile */ @@ -9824,14 +9926,16 @@ static OPJ_BOOL opj_j2k_decode_one_tile ( opj_j2k_t *p_j2k, * so move to the last SOT read */ if ( !(opj_stream_read_seek(p_stream, p_j2k->m_specific_param.m_decoder.m_last_sot_read_pos+2, p_manager)) ){ opj_event_msg(p_manager, EVT_ERROR, "Problem with seek function\n"); - opj_free(l_current_data); + if (l_current_data) + opj_free(l_current_data); return OPJ_FALSE; } } else{ if ( !(opj_stream_read_seek(p_stream, p_j2k->cstr_index->tile_index[l_tile_no_to_dec].tp_index[0].start_pos+2, p_manager)) ) { opj_event_msg(p_manager, EVT_ERROR, "Problem with seek function\n"); - opj_free(l_current_data); + if (l_current_data) + opj_free(l_current_data); return OPJ_FALSE; } } @@ -9850,15 +9954,16 @@ static OPJ_BOOL opj_j2k_decode_one_tile ( opj_j2k_t *p_j2k, &l_go_on, p_stream, p_manager)) { - opj_free(l_current_data); - return OPJ_FALSE; + if (l_current_data) + opj_free(l_current_data); + return OPJ_FALSE; } if (! l_go_on) { break; } - if (l_data_size > l_max_data_size) { + if (l_current_data && l_data_size > l_max_data_size) { OPJ_BYTE *l_new_current_data = (OPJ_BYTE *) opj_realloc(l_current_data, l_data_size); if (! l_new_current_data) { opj_free(l_current_data); @@ -9873,23 +9978,28 @@ static OPJ_BOOL opj_j2k_decode_one_tile ( opj_j2k_t *p_j2k, } if (! opj_j2k_decode_tile(p_j2k,l_current_tile_no,l_current_data,l_data_size,p_stream,p_manager)) { - opj_free(l_current_data); + if (l_current_data) + opj_free(l_current_data); return OPJ_FALSE; } opj_event_msg(p_manager, EVT_INFO, "Tile %d/%d has been decoded.\n", l_current_tile_no, (p_j2k->m_cp.th * p_j2k->m_cp.tw) - 1); - - if (! opj_j2k_update_image_data(p_j2k->m_tcd,l_current_data, p_j2k->m_output_image)) { - opj_free(l_current_data); - return OPJ_FALSE; - } + + if (l_current_data) { + if (!opj_j2k_update_image_data(p_j2k->m_tcd, l_current_data, p_j2k->m_output_image)) { + opj_free(l_current_data); + return OPJ_FALSE; + } + } opj_event_msg(p_manager, EVT_INFO, "Image data has been updated with tile %d.\n\n", l_current_tile_no); + if(l_current_tile_no == l_tile_no_to_dec) { /* move into the codestream to the first SOT (FIXME or not move?)*/ if (!(opj_stream_read_seek(p_stream, p_j2k->cstr_index->main_head_end + 2, p_manager) ) ) { opj_event_msg(p_manager, EVT_ERROR, "Problem with seek function\n"); - opj_free(l_current_data); + if (l_current_data) + opj_free(l_current_data); return OPJ_FALSE; } break; @@ -9900,7 +10010,8 @@ static OPJ_BOOL opj_j2k_decode_one_tile ( opj_j2k_t *p_j2k, } - opj_free(l_current_data); + if (l_current_data) + opj_free(l_current_data); return OPJ_TRUE; } @@ -9927,10 +10038,8 @@ OPJ_BOOL opj_j2k_decode(opj_j2k_t * p_j2k, opj_image_t * p_image, opj_event_mgr_t * p_manager) { - OPJ_UINT32 compno; - if (!p_image) - return OPJ_FALSE; + return OPJ_FALSE; p_j2k->m_output_image = opj_image_create0(); if (! (p_j2k->m_output_image)) { @@ -9948,20 +10057,8 @@ OPJ_BOOL opj_j2k_decode(opj_j2k_t * p_j2k, return OPJ_FALSE; } - /* Move data and copy one information from codec to output image*/ - for (compno = 0; compno < p_image->numcomps; compno++) { - p_image->comps[compno].resno_decoded = p_j2k->m_output_image->comps[compno].resno_decoded; - p_image->comps[compno].data = p_j2k->m_output_image->comps[compno].data; -#if 0 - char fn[256]; - sprintf( fn, "/tmp/%d.raw", compno ); - FILE *debug = fopen( fn, "wb" ); - fwrite( p_image->comps[compno].data, sizeof(OPJ_INT32), p_image->comps[compno].w * p_image->comps[compno].h, debug ); - fclose( debug ); -#endif - p_j2k->m_output_image->comps[compno].data = NULL; - } - + /* Move data and information from codec output image to user output image*/ + opj_j2k_transfer_image_data(p_j2k->m_output_image, p_image); return OPJ_TRUE; } @@ -10044,17 +10141,8 @@ OPJ_BOOL opj_j2k_get_tile( opj_j2k_t *p_j2k, return OPJ_FALSE; } - /* Move data and copy one information from codec to output image*/ - for (compno = 0; compno < p_image->numcomps; compno++) { - p_image->comps[compno].resno_decoded = p_j2k->m_output_image->comps[compno].resno_decoded; - - if (p_image->comps[compno].data) - opj_free(p_image->comps[compno].data); - - p_image->comps[compno].data = p_j2k->m_output_image->comps[compno].data; - - p_j2k->m_output_image->comps[compno].data = NULL; - } + /* Move data information from codec output image to user output image*/ + opj_j2k_transfer_image_data(p_j2k->m_output_image, p_image); return OPJ_TRUE; } @@ -10120,9 +10208,8 @@ OPJ_BOOL opj_j2k_encode(opj_j2k_t * p_j2k, } for (i=0;im_tcd); if (!l_reuse_data) { if (l_current_tile_size > l_max_tile_size) { - OPJ_BYTE *l_new_current_data = (OPJ_BYTE *) opj_realloc(l_current_data, l_current_tile_size); - if (! l_new_current_data) { - if (l_current_data) { - opj_free(l_current_data); - } - opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to encode all tiles\n"); - return OPJ_FALSE; - } - l_current_data = l_new_current_data; - l_max_tile_size = l_current_tile_size; + OPJ_BYTE *l_new_current_data = (OPJ_BYTE *) opj_realloc(l_current_data, l_current_tile_size); + if (! l_new_current_data) { + if (l_current_data) { + opj_free(l_current_data); + } + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to encode all tiles\n"); + return OPJ_FALSE; + } + l_current_data = l_new_current_data; + l_max_tile_size = l_current_tile_size; } /* copy image data (32 bit) to l_current_data as contiguous, all-component, zero offset buffer */ @@ -10181,7 +10268,7 @@ OPJ_BOOL opj_j2k_encode(opj_j2k_t * p_j2k, } if (l_current_data) { - opj_free(l_current_data); + opj_free(l_current_data); } return OPJ_TRUE; } diff --git a/src/lib/openjp2/j2k.h b/src/lib/openjp2/j2k.h index 358e07396..f0aa33d32 100644 --- a/src/lib/openjp2/j2k.h +++ b/src/lib/openjp2/j2k.h @@ -280,10 +280,9 @@ typedef struct opj_tcp opj_tccp_t *tccps; /** number of tile parts for the tile. */ OPJ_UINT32 m_nb_tile_parts; - /** data for the tile */ - OPJ_BYTE * m_data; - /** size of data */ - OPJ_UINT32 m_data_size; + + opj_seg_buf_t m_data; + /** encoding norms */ OPJ_FLOAT64 * mct_norms; /** the mct decoding matrix */ diff --git a/src/lib/openjp2/jp2.c b/src/lib/openjp2/jp2.c index 6c6f6e835..4bcc1007c 100644 --- a/src/lib/openjp2/jp2.c +++ b/src/lib/openjp2/jp2.c @@ -979,21 +979,22 @@ static void opj_jp2_apply_pclr(opj_image_t *image, opj_jp2_color_t *color) return; } for(i = 0; i < nr_channels; ++i) { - pcol = cmap[i].pcol; cmp = cmap[i].cmp; + pcol = cmap[i].pcol; + cmp = cmap[i].cmp; /* Direct use */ - if(cmap[i].mtyp == 0){ - assert( pcol == 0 ); - new_comps[i] = old_comps[cmp]; - } else { - assert( i == pcol ); - new_comps[pcol] = old_comps[cmp]; - } + if(cmap[i].mtyp == 0){ + assert( pcol == 0 ); + new_comps[i] = old_comps[cmp]; + new_comps[i].data = NULL; + } else { + assert( i == pcol ); + new_comps[pcol] = old_comps[cmp]; + new_comps[pcol].data = NULL; + } /* Palette mapping: */ - new_comps[i].data = (OPJ_INT32*) - opj_malloc(old_comps[cmp].w * old_comps[cmp].h * sizeof(OPJ_INT32)); - if (!new_comps[i].data) { + if (!opj_image_single_component_data_alloc(new_comps + i)) { opj_free(new_comps); new_comps = NULL; /* FIXME no error code for opj_jp2_apply_pclr */ @@ -1037,10 +1038,9 @@ static void opj_jp2_apply_pclr(opj_image_t *image, opj_jp2_color_t *color) } max = image->numcomps; - for(i = 0; i < max; ++i) { - if(old_comps[i].data) opj_free(old_comps[i].data); + for (i = 0; i < max; ++i) { + opj_image_single_component_data_free(old_comps + i); } - opj_free(old_comps); image->comps = new_comps; image->numcomps = nr_channels; diff --git a/src/lib/openjp2/openjpeg.c b/src/lib/openjp2/openjpeg.c index 5114cc108..9d9c5249e 100644 --- a/src/lib/openjp2/openjpeg.c +++ b/src/lib/openjp2/openjpeg.c @@ -33,11 +33,38 @@ #ifdef _WIN32 #include -#endif /* _WIN32 */ +#else /* _WIN32 */ + +#include + +#include +#include +#include +# include +# include + +#endif + +#include #include "opj_includes.h" +#ifdef _OPENMP +#include +#endif + +static OPJ_BOOL is_initialized = OPJ_FALSE; +OPJ_BOOL OPJ_CALLCONV opj_initialize() { + if (!is_initialized) { +#ifdef _OPENMP + omp_set_num_threads(OPJ_NUM_CORES); +#endif + is_initialized = OPJ_TRUE; + } + return OPJ_TRUE; +} + /* ---------------------------------------------------------------------- */ /* Functions to set the message handlers */ @@ -129,6 +156,100 @@ static OPJ_BOOL opj_seek_from_file (OPJ_OFF_T p_nb_bytes, FILE * p_user_data) } /* ---------------------------------------------------------------------- */ + +#ifdef _WIN32 +typedef void* opj_handle_t; +#else +typedef OPJ_INT32 opj_handle_t; +#endif + + +typedef struct opj_buf_info +{ + OPJ_BYTE *buf; + OPJ_OFF_T off; + OPJ_SIZE_T len; + opj_handle_t fd; // for file mapping +} opj_buf_info_t; + +static void opj_free_buffer_info(void* user_data) { + if (user_data) + opj_free(user_data); +} + +static OPJ_SIZE_T opj_zero_copy_read_from_buffer(void ** p_buffer, + OPJ_SIZE_T p_nb_bytes, + opj_buf_info_t* p_source_buffer) +{ + OPJ_SIZE_T l_nb_read = 0; + + if ( ((OPJ_SIZE_T)p_source_buffer->off + p_nb_bytes) < p_source_buffer->len){ + l_nb_read = p_nb_bytes; + } + + *p_buffer = p_source_buffer->buf + p_source_buffer->off; + p_source_buffer->off += (OPJ_OFF_T)l_nb_read; + + return l_nb_read ? l_nb_read : ((OPJ_SIZE_T)-1); +} + +static OPJ_SIZE_T opj_read_from_buffer(void * p_buffer, + OPJ_SIZE_T p_nb_bytes, + opj_buf_info_t* p_source_buffer) +{ + OPJ_SIZE_T l_nb_read; + + if ((OPJ_SIZE_T)p_source_buffer->off + p_nb_bytes < p_source_buffer->len){ + l_nb_read = p_nb_bytes; + } + else{ + l_nb_read = (p_source_buffer->len - (OPJ_SIZE_T)p_source_buffer->off); + } + memcpy(p_buffer, p_source_buffer->buf + p_source_buffer->off, l_nb_read); + p_source_buffer->off += (OPJ_OFF_T)l_nb_read; + + return l_nb_read ? l_nb_read : ((OPJ_SIZE_T)-1); +} + +static OPJ_SIZE_T opj_write_from_buffer(void * p_buffer, + OPJ_SIZE_T p_nb_bytes, + opj_buf_info_t* p_source_buffer) +{ + memcpy(p_source_buffer->buf + (OPJ_SIZE_T)p_source_buffer->off, p_buffer, p_nb_bytes); + p_source_buffer->off += (OPJ_OFF_T)p_nb_bytes; + p_source_buffer->len += p_nb_bytes; + + return p_nb_bytes; +} + +static OPJ_OFF_T opj_skip_from_buffer(OPJ_OFF_T p_nb_bytes, + opj_buf_info_t * p_source_buffer) +{ + if (p_source_buffer->off + p_nb_bytes < (OPJ_OFF_T)p_source_buffer->len) { + p_source_buffer->off += p_nb_bytes; + } + else { + p_source_buffer->off = (OPJ_OFF_T)p_source_buffer->len; + } + return p_nb_bytes; +} + +static OPJ_BOOL opj_seek_from_buffer(OPJ_OFF_T p_nb_bytes, + opj_buf_info_t * p_source_buffer) +{ + if (p_nb_bytes < (OPJ_OFF_T)p_source_buffer->len) { + p_source_buffer->off = p_nb_bytes; + } + else { + p_source_buffer->off = (OPJ_OFF_T)p_source_buffer->len; + } + return OPJ_TRUE; +} + +/* ---------------------------------------------------------------------- */ + + + #ifdef _WIN32 #ifndef OPJ_STATIC BOOL APIENTRY @@ -401,6 +522,9 @@ OPJ_BOOL OPJ_CALLCONV opj_decode( opj_codec_t *p_codec, opj_stream_t *p_stream, opj_image_t* p_image) { + if (!opj_initialize()) + return OPJ_FALSE; + if (p_codec && p_stream) { opj_codec_private_t * l_codec = (opj_codec_private_t *) p_codec; opj_stream_private_t * l_stream = (opj_stream_private_t *) p_stream; @@ -729,6 +853,9 @@ OPJ_BOOL OPJ_CALLCONV opj_start_compress ( opj_codec_t *p_codec, OPJ_BOOL OPJ_CALLCONV opj_encode(opj_codec_t *p_info, opj_stream_t *p_stream) { + if (!opj_initialize()) + return OPJ_FALSE; + if (p_info && p_stream) { opj_codec_private_t * l_codec = (opj_codec_private_t *) p_info; opj_stream_private_t * l_stream = (opj_stream_private_t *) p_stream; @@ -917,6 +1044,8 @@ void OPJ_CALLCONV opj_destroy_cstr_index(opj_codestream_index_t **p_cstr_index) } } +/* ---------------------------------------------------------------------- */ + opj_stream_t* OPJ_CALLCONV opj_stream_create_default_file_stream (const char *fname, OPJ_BOOL p_is_read_stream) { return opj_stream_create_file_stream(fname, OPJ_J2K_STREAM_CHUNK_SIZE, p_is_read_stream); @@ -958,3 +1087,309 @@ opj_stream_t* OPJ_CALLCONV opj_stream_create_file_stream ( return l_stream; } + +/* ---------------------------------------------------------------------- */ + +static void opj_set_up_buffer_stream(opj_stream_t* l_stream, OPJ_SIZE_T len, OPJ_BOOL p_is_read_stream) { + opj_stream_set_user_data_length(l_stream, len); + + if (p_is_read_stream) { + opj_stream_set_read_function(l_stream, (opj_stream_read_fn)opj_read_from_buffer); + opj_stream_set_zero_copy_read_function(l_stream, (opj_stream_zero_copy_read_fn)opj_zero_copy_read_from_buffer); + } + else + opj_stream_set_write_function(l_stream, (opj_stream_write_fn)opj_write_from_buffer); + opj_stream_set_skip_function(l_stream, (opj_stream_skip_fn)opj_skip_from_buffer); + opj_stream_set_seek_function(l_stream, (opj_stream_seek_fn)opj_seek_from_buffer); +} + +opj_stream_t* OPJ_CALLCONV opj_stream_create_buffer_stream(OPJ_BYTE *buf, + OPJ_SIZE_T len, + OPJ_BOOL p_is_read_stream) +{ + opj_stream_t* l_stream; + opj_buf_info_t* p_source_buffer = NULL; + + if (!buf || !len) + return NULL; + + p_source_buffer = (opj_buf_info_t*)opj_malloc(sizeof(opj_buf_info_t)); + if (!p_source_buffer) + return NULL; + + l_stream = opj_stream_create(0,p_is_read_stream); + if (!l_stream) { + opj_free(p_source_buffer); + return NULL; + + } + + memset(p_source_buffer, 0, sizeof(opj_buf_info_t)); + p_source_buffer->buf = buf; + p_source_buffer->off = 0; + p_source_buffer->len = len; + + opj_stream_set_user_data(l_stream, p_source_buffer, opj_free_buffer_info); + opj_set_up_buffer_stream(l_stream, p_source_buffer->len, p_is_read_stream); + return l_stream; +} + +/* ---------------------------------------------------------------------- */ + +OPJ_INT32 opj_get_file_open_mode(const char* mode) +{ + OPJ_INT32 m = -1; + switch (mode[0]) { + case 'r': + m = O_RDONLY; + if (mode[1] == '+') + m = O_RDWR; + break; + case 'w': + case 'a': + m = O_RDWR | O_CREAT; + if (mode[0] == 'w') + m |= O_TRUNC; + break; + default: + break; + } + return m; +} + + +#ifdef _WIN32 + +static OPJ_UINT64 opj_size_proc(opj_handle_t fd) +{ + ULARGE_INTEGER m; + m.LowPart = GetFileSize(fd, &m.HighPart); + return(m.QuadPart); +} + + +static void* opj_map(opj_handle_t fd, OPJ_SIZE_T len) { + void* ptr = NULL; + HANDLE hMapFile = NULL; + + if (!fd || !len) + return NULL; + + /* Passing in 0 for the maximum file size indicates that we + would like to create a file mapping object for the full file size */ + hMapFile = CreateFileMapping(fd, NULL, PAGE_READONLY, 0, 0, NULL); + if (hMapFile == NULL) { + return NULL; + } + ptr = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0); + CloseHandle(hMapFile); + return ptr; +} + +static OPJ_INT32 opj_unmap(void* ptr, OPJ_SIZE_T len){ + OPJ_INT32 rc = -1; + (void)len; + if (ptr) + rc = UnmapViewOfFile(ptr) ? 0 : -1; + return rc; +} + +static opj_handle_t opj_open_fd(const char* fname, const char* mode) { + void* fd = NULL; + OPJ_INT32 m = -1; + DWORD dwMode = 0; + + if (!fname) + return (opj_handle_t)-1; + + + m = opj_get_file_open_mode(mode); + switch (m) { + case O_RDONLY: + dwMode = OPEN_EXISTING; + break; + case O_RDWR: + dwMode = OPEN_ALWAYS; + break; + case O_RDWR | O_CREAT: + dwMode = OPEN_ALWAYS; + break; + case O_RDWR | O_TRUNC: + dwMode = CREATE_ALWAYS; + break; + case O_RDWR | O_CREAT | O_TRUNC: + dwMode = CREATE_ALWAYS; + break; + default: + return NULL; + } + + fd = (opj_handle_t)CreateFileA(fname, + (m == O_RDONLY) ? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE), + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, dwMode, + (m == O_RDONLY) ? FILE_ATTRIBUTE_READONLY : FILE_ATTRIBUTE_NORMAL, + NULL); + if (fd == INVALID_HANDLE_VALUE) { + return (opj_handle_t)-1; + } + return fd; +} + +static OPJ_INT32 opj_close_fd(opj_handle_t fd) { + OPJ_INT32 rc = -1; + if (fd) { + rc = CloseHandle(fd) ? 0 : -1; + } + return rc; +} + +#else + +static OPJ_UINT64 opj_size_proc(opj_handle_t fd) +{ + struct stat sb; + if (!fd) + return 0; + + if (fstat(fd, &sb)<0) + return(0); + else + return((OPJ_UINT64)sb.st_size); +} + +static void* opj_map(opj_handle_t fd, OPJ_SIZE_T len) { + void* ptr = NULL; + OPJ_UINT64 size64 = 0; + + if (!fd) + return NULL; + + size64 = opj_size_proc(fd); + ptr = (void*)mmap(0, (size_t)size64, PROT_READ, MAP_SHARED, fd, 0); + return ptr == (void*)-1 ? NULL : ptr; +} + +static OPJ_INT32 opj_unmap(void* ptr, OPJ_SIZE_T len) { + if (ptr) + munmap(ptr, len); + return 0; +} + +static opj_handle_t opj_open_fd(const char* fname, const char* mode) { + opj_handle_t fd = 0; + OPJ_INT32 m = -1; + if (!fname) { + return (opj_handle_t )-1; + } + m = opj_get_file_open_mode(mode); + fd = open(fname, m, 0666); + if (fd < 0) { +#ifdef DEBUG_ERRNO + if (errno > 0 && strerror(errno) != NULL) { + printf("%s: %s", fname, strerror(errno)); + } + else { + printf("%s: Cannot open", fname); + } +#endif + return (opj_handle_t )-1; + } + return fd; +} + +static OPJ_INT32 opj_close_fd(opj_handle_t fd) { + if (!fd) + return 0; + return (close(fd)); +} + +#endif + + + +static void opj_mem_map_free(void* user_data) { + if (user_data) { + opj_buf_info_t* buffer_info = (opj_buf_info_t*)user_data; + opj_unmap(buffer_info->buf, buffer_info->len); + opj_close_fd(buffer_info->fd); + opj_free(buffer_info); + } +} + +/* +Currently, only read streams are supported for memory mapped files. +*/ +opj_stream_t* OPJ_CALLCONV opj_stream_create_mapped_file_read_stream(const char *fname) +{ + opj_stream_t* l_stream = NULL; + opj_buf_info_t* buffer_info = NULL; + void* mapped_view = NULL; + OPJ_BOOL p_is_read_stream = OPJ_TRUE; + + opj_handle_t fd = opj_open_fd(fname, p_is_read_stream ? "r" : "w"); + if (fd == (opj_handle_t)-1) + return NULL; + + buffer_info = (opj_buf_info_t*)opj_malloc(sizeof(opj_buf_info_t)); + memset(buffer_info, 0, sizeof(opj_buf_info_t)); + buffer_info->fd = fd; + buffer_info->len = (OPJ_SIZE_T)opj_size_proc(fd); + + l_stream = opj_stream_create(0, p_is_read_stream); + if (!l_stream) { + opj_mem_map_free(buffer_info); + return NULL; + } + + mapped_view = opj_map(fd, buffer_info->len); + if (!mapped_view) { + opj_stream_destroy(l_stream); + opj_mem_map_free(buffer_info); + return NULL; + } + + buffer_info->buf = mapped_view; + buffer_info->off = 0; + + opj_stream_set_user_data(l_stream, buffer_info, (opj_stream_free_user_data_fn)opj_mem_map_free); + opj_set_up_buffer_stream(l_stream, buffer_info->len, p_is_read_stream); + + + return l_stream; +} + +void OPJ_CALLCONV opj_image_all_components_data_free(opj_image_t* image) { + OPJ_UINT32 i; + if (!image || !image->comps) + return; + for (i = 0; i < image->numcomps; ++i) { + opj_image_single_component_data_free(image->comps + i); + } +} + + +OPJ_BOOL OPJ_CALLCONV opj_image_single_component_data_alloc(opj_image_comp_t* comp) { + OPJ_INT32* data = NULL; + if (!comp) + return OPJ_FALSE; + + data = (OPJ_INT32*)opj_malloc(comp->w * comp->h * sizeof(OPJ_UINT32)); + if (!data) + return OPJ_FALSE; + opj_image_single_component_data_free(comp); + comp->data = data; + return OPJ_TRUE; +} + +void OPJ_CALLCONV opj_image_single_component_data_free(opj_image_comp_t* comp) { + if (!comp) + return; + if (comp->data) { + /*opj_aligned_free(comp->data);*/ + opj_free(comp->data); + comp->data = NULL; + } +} + + + diff --git a/src/lib/openjp2/openjpeg.h b/src/lib/openjp2/openjpeg.h index c07e9c84b..13867cda7 100644 --- a/src/lib/openjp2/openjpeg.h +++ b/src/lib/openjp2/openjpeg.h @@ -592,6 +592,12 @@ typedef void * opj_codec_t; */ typedef OPJ_SIZE_T (* opj_stream_read_fn) (void * p_buffer, OPJ_SIZE_T p_nb_bytes, void * p_user_data) ; +/* +* Callback function prototype for zero copy read function +*/ +typedef OPJ_SIZE_T(*opj_stream_zero_copy_read_fn) (void ** p_buffer, OPJ_SIZE_T p_nb_bytes, void * p_user_data); + + /* * Callback function prototype for write function */ @@ -1054,6 +1060,9 @@ extern "C" { /* Get the version of the openjpeg library*/ OPJ_API const char * OPJ_CALLCONV opj_version(void); +/* Initialize OpenJPEG library */ +OPJ_API OPJ_BOOL OPJ_CALLCONV opj_initialize(); + /* ========================================================== image functions definitions @@ -1128,6 +1137,15 @@ OPJ_API void OPJ_CALLCONV opj_stream_destroy(opj_stream_t* p_stream); */ OPJ_API void OPJ_CALLCONV opj_stream_set_read_function(opj_stream_t* p_stream, opj_stream_read_fn p_function); +/** +* Sets the given function to be used as a zero copy read function. +* NOTE: this feature is only available for memory mapped and buffer backed streams, not file streams +* @param p_stream the stream to modify +* @param p_function the function to use a read function. +*/ +OPJ_API void OPJ_CALLCONV opj_stream_set_zero_copy_read_function(opj_stream_t* p_stream, opj_stream_zero_copy_read_fn p_function); + + /** * Sets the given function to be used as a write function. * @param p_stream the stream to modify @@ -1180,6 +1198,11 @@ OPJ_API opj_stream_t* OPJ_CALLCONV opj_stream_create_default_file_stream (const OPJ_API opj_stream_t* OPJ_CALLCONV opj_stream_create_file_stream (const char *fname, OPJ_SIZE_T p_buffer_size, OPJ_BOOL p_is_read_stream); +OPJ_API opj_stream_t* OPJ_CALLCONV opj_stream_create_buffer_stream(OPJ_BYTE *buf, + OPJ_SIZE_T len, + OPJ_BOOL p_is_read_stream); + +OPJ_API opj_stream_t* OPJ_CALLCONV opj_stream_create_mapped_file_read_stream(const char *fname); /* ========================================================== @@ -1554,7 +1577,11 @@ OPJ_API OPJ_BOOL OPJ_CALLCONV opj_set_MCT( opj_cparameters_t *parameters, OPJ_INT32 * p_dc_shift, OPJ_UINT32 pNbComp); +OPJ_API void OPJ_CALLCONV opj_image_all_components_data_free(opj_image_t* image); + +OPJ_API void OPJ_CALLCONV opj_image_single_component_data_free(opj_image_comp_t* image); +OPJ_API OPJ_BOOL OPJ_CALLCONV opj_image_single_component_data_alloc(opj_image_comp_t* image); #ifdef __cplusplus } diff --git a/src/lib/openjp2/opj_clock.c b/src/lib/openjp2/opj_clock.c index bb4cae734..3df73a579 100644 --- a/src/lib/openjp2/opj_clock.c +++ b/src/lib/openjp2/opj_clock.c @@ -48,7 +48,7 @@ OPJ_FLOAT64 opj_clock(void) { /* cout << "freq = " << ((double) freq.QuadPart) << endl; */ /* t is the high resolution performance counter (see MSDN) */ QueryPerformanceCounter ( & t ) ; - return ( t.QuadPart /(OPJ_FLOAT64) freq.QuadPart ) ; + return (OPJ_FLOAT64)t.QuadPart /(OPJ_FLOAT64) freq.QuadPart ; #else /* Unix or Linux: use resource usage */ struct rusage t; diff --git a/src/lib/openjp2/opj_includes.h b/src/lib/openjp2/opj_includes.h index f855b7c66..8baa4964f 100644 --- a/src/lib/openjp2/opj_includes.h +++ b/src/lib/openjp2/opj_includes.h @@ -177,6 +177,8 @@ static INLINE long opj_lrintf(float f) { #include "opj_malloc.h" #include "event.h" #include "function_list.h" +#include "vector.h" +#include "segmented_stream.h" #include "bio.h" #include "cio.h" @@ -193,6 +195,7 @@ static INLINE long opj_lrintf(float f) { #include "tgt.h" #include "tcd.h" #include "t1.h" +#include "t1_opt.h" #include "dwt.h" #include "t2.h" #include "mct.h" diff --git a/src/lib/openjp2/segmented_stream.c b/src/lib/openjp2/segmented_stream.c new file mode 100644 index 000000000..61e6212c2 --- /dev/null +++ b/src/lib/openjp2/segmented_stream.c @@ -0,0 +1,411 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2002-2016, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2016, OpenJPEG contributors + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opj_includes.h" + +/* #define DEBUG_SEG_BUF */ + + +OPJ_BOOL opj_min_buf_vec_copy_to_contiguous_buffer(opj_vec_t* min_buf_vec, OPJ_BYTE* buffer) { + OPJ_INT32 i = 0; + OPJ_SIZE_T offset = 0; + + if (!buffer || !min_buf_vec) + return OPJ_FALSE; + + for (i = 0; i < min_buf_vec->size; ++i) { + opj_min_buf_t* seg = (opj_min_buf_t*)opj_vec_get(min_buf_vec, i); + if (seg->len) + memcpy(buffer + offset, seg->buf, seg->len); + offset += seg->len; + } + return OPJ_TRUE; + +} + +OPJ_BOOL opj_min_buf_vec_push_back(opj_vec_t* buf_vec, OPJ_BYTE* buf, OPJ_UINT16 len) { + opj_min_buf_t* seg = NULL; + if (!buf_vec || !buf || !len) + return OPJ_FALSE; + + if (!buf_vec->data) { + opj_vec_init(buf_vec); + buf_vec->owns_data = OPJ_TRUE; + } + + seg = (opj_min_buf_t*)opj_malloc(sizeof(opj_buf_t)); + if (!seg) + return OPJ_FALSE; + + seg->buf = buf; + seg->len = len; + if (!opj_vec_push_back(buf_vec, seg)) { + opj_free(seg); + return OPJ_FALSE; + } + + return OPJ_TRUE; +} + +OPJ_UINT16 opj_min_buf_vec_get_len(opj_vec_t* min_buf_vec) { + OPJ_INT32 i = 0; + OPJ_UINT16 len = 0; + if (!min_buf_vec || !min_buf_vec->data) + return 0; + for (i = 0; i < min_buf_vec->size; ++i) { + opj_min_buf_t* seg = (opj_min_buf_t*)opj_vec_get(min_buf_vec, i); + if (seg) + len += seg->len; + } + return len; + +} + + + +/*--------------------------------------------------------------------------*/ + +/* Segmented Buffer Stream */ + +static void opj_seg_buf_increment(opj_seg_buf_t * seg_buf) +{ + opj_buf_t* cur_seg = NULL; + if (seg_buf == NULL || seg_buf->cur_seg_id == seg_buf->segments.size-1) { + return; + } + + cur_seg = (opj_buf_t*)opj_vec_get(&seg_buf->segments, seg_buf->cur_seg_id); + if ((OPJ_SIZE_T)cur_seg->offset == cur_seg->len && + seg_buf->cur_seg_id < seg_buf->segments.size -1) { + seg_buf->cur_seg_id++; + } +} + +static OPJ_SIZE_T opj_seg_buf_read(opj_seg_buf_t * seg_buf, + void * p_buffer, + OPJ_SIZE_T p_nb_bytes) +{ + OPJ_SIZE_T bytes_in_current_segment; + OPJ_SIZE_T bytes_to_read; + OPJ_SIZE_T total_bytes_read; + OPJ_SIZE_T bytes_left_to_read; + OPJ_SIZE_T bytes_remaining_in_file; + + if (p_buffer == NULL || p_nb_bytes == 0 || seg_buf == NULL) + return 0; + + /*don't try to read more bytes than are available */ + bytes_remaining_in_file = seg_buf->data_len - (OPJ_SIZE_T)opj_seg_buf_get_global_offset(seg_buf); + if (p_nb_bytes > bytes_remaining_in_file) { +#ifdef DEBUG_SEG_BUF + printf("Warning: attempt to read past end of segmented buffer\n"); +#endif + p_nb_bytes = bytes_remaining_in_file; + } + + total_bytes_read = 0; + bytes_left_to_read = p_nb_bytes; + while (bytes_left_to_read > 0 && seg_buf->cur_seg_id < seg_buf->segments.size) { + opj_buf_t* cur_seg = (opj_buf_t*)opj_vec_get(&seg_buf->segments, seg_buf->cur_seg_id); + bytes_in_current_segment = (cur_seg->len - (OPJ_SIZE_T)cur_seg->offset); + + bytes_to_read = (bytes_left_to_read < bytes_in_current_segment) ? + bytes_left_to_read : bytes_in_current_segment; + + if (p_buffer) { + memcpy((OPJ_BYTE*)p_buffer + total_bytes_read,cur_seg->buf + cur_seg->offset, bytes_to_read); + } + opj_seg_buf_incr_cur_seg_offset(seg_buf,(OPJ_OFF_T)bytes_to_read); + + total_bytes_read += bytes_to_read; + bytes_left_to_read -= bytes_to_read; + + + } + return total_bytes_read ? total_bytes_read : (OPJ_SIZE_T)-1; +} + +/* Disable this method for now, since it is not needed at the moment */ +#if 0 +static OPJ_OFF_T opj_seg_buf_skip(OPJ_OFF_T p_nb_bytes, opj_seg_buf_t * seg_buf) +{ + OPJ_SIZE_T bytes_in_current_segment; + OPJ_SIZE_T bytes_remaining; + + if (!seg_buf) + return p_nb_bytes; + + if (p_nb_bytes + opj_seg_buf_get_global_offset(seg_buf)> (OPJ_OFF_T)seg_buf->data_len) { +#ifdef DEBUG_SEG_BUF + printf("Warning: attempt to skip past end of segmented buffer\n"); +#endif + return p_nb_bytes; + } + + if (p_nb_bytes == 0) + return 0; + + bytes_remaining = (OPJ_SIZE_T)p_nb_bytes; + while (seg_buf->cur_seg_id < seg_buf->segments.size && bytes_remaining > 0) { + + opj_buf_t* cur_seg = (opj_buf_t*)opj_vec_get(&seg_buf->segments, seg_buf->cur_seg_id); + bytes_in_current_segment = (OPJ_SIZE_T)(cur_seg->len -cur_seg->offset); + + /* hoover up all the bytes in this segment, and move to the next one */ + if (bytes_in_current_segment > bytes_remaining) { + + opj_seg_buf_incr_cur_seg_offset(seg_buf, bytes_in_current_segment); + + bytes_remaining -= bytes_in_current_segment; + cur_seg = (opj_buf_t*)opj_vec_get(&seg_buf->segments, seg_buf->cur_seg_id); + } + else /* bingo! we found the segment */ + { + opj_seg_buf_incr_cur_seg_offset(seg_buf, bytes_remaining); + return p_nb_bytes; + } + } + return p_nb_bytes; +} +#endif +static OPJ_BOOL opj_seg_buf_add_segment(opj_seg_buf_t* seg_buf, OPJ_BYTE* buf, OPJ_SIZE_T len) { + opj_buf_t* new_seg = NULL; + if (!seg_buf) + return OPJ_FALSE; + new_seg = (opj_buf_t*)opj_malloc(sizeof(opj_buf_t)); + if (!new_seg) + return OPJ_FALSE; + + memset(new_seg, 0, sizeof(opj_buf_t)); + new_seg->buf = buf; + new_seg->len = len; + if (!opj_vec_push_back(&seg_buf->segments, new_seg)) { + opj_free(new_seg); + return OPJ_FALSE; + } + + seg_buf->cur_seg_id = seg_buf->segments.size - 1; + seg_buf->data_len += len; + return OPJ_TRUE; +} + +/*--------------------------------------------------------------------------*/ + +void opj_seg_buf_cleanup(opj_seg_buf_t* seg_buf) { + OPJ_INT32 i; + if (!seg_buf) + return; + for (i = 0; i < seg_buf->segments.size; ++i) { + opj_buf_t* seg = (opj_buf_t*)opj_vec_get(&seg_buf->segments, i); + if (seg) { + opj_buf_free(seg); + } + } + opj_vec_cleanup(&seg_buf->segments); +} + +void opj_seg_buf_rewind(opj_seg_buf_t* seg_buf) { + OPJ_INT32 i; + if (!seg_buf) + return; + for (i = 0; i < seg_buf->segments.size; ++i) { + opj_buf_t* seg = (opj_buf_t*)opj_vec_get(&seg_buf->segments, i); + if (seg) { + seg->offset = 0; + } + } + seg_buf->cur_seg_id = 0; +} + + +OPJ_BOOL opj_seg_buf_push_back(opj_seg_buf_t* seg_buf, OPJ_BYTE* buf, OPJ_SIZE_T len) { + opj_buf_t* seg = NULL; + if (!seg_buf || !buf || !len) + return OPJ_FALSE; + + if (!seg_buf->segments.data) { + opj_vec_init(&seg_buf->segments); + /* let segmented buffer free the segment and its internal buffer, + so don't make vector manage memory */ + seg_buf->segments.owns_data = OPJ_FALSE; + } + + + if (!opj_seg_buf_add_segment(seg_buf, buf, len)) + return OPJ_FALSE; + + seg = (opj_buf_t*)opj_vec_back(&seg_buf->segments); + seg->owns_data = OPJ_FALSE; + return OPJ_TRUE; +} + +OPJ_BOOL opj_seg_buf_alloc_and_push_back(opj_seg_buf_t* seg_buf, OPJ_SIZE_T len) { + opj_buf_t* seg = NULL; + OPJ_BYTE* buf = NULL; + if (!seg_buf || !len) + return OPJ_FALSE; + + if (!seg_buf->segments.data) { + opj_vec_init(&seg_buf->segments); + /* we want to free the segment and its internal buffer, so don't make vector manage memory*/ + seg_buf->segments.owns_data = OPJ_FALSE; + } + + + buf = (OPJ_BYTE*)opj_malloc(len); + if (!buf) + return OPJ_FALSE; + + if (!opj_seg_buf_add_segment(seg_buf, buf, len)) { + opj_free(buf); + return OPJ_FALSE; + } + + seg = (opj_buf_t*)opj_vec_back(&seg_buf->segments); + seg->owns_data = OPJ_TRUE; + + return OPJ_TRUE; +} + +void opj_seg_buf_incr_cur_seg_offset(opj_seg_buf_t* seg_buf, OPJ_OFF_T offset) { + opj_buf_t* cur_seg = NULL; + if (!seg_buf) + return; + cur_seg = (opj_buf_t*)(seg_buf->segments.data[seg_buf->cur_seg_id]); + opj_buf_incr_offset(cur_seg, offset); + if ((OPJ_SIZE_T)cur_seg->offset == cur_seg->len) { + opj_seg_buf_increment(seg_buf); + } + +} + + +/** +* Zero copy read of contiguous chunk from current segment. +* Returns OPJ_FALSE if unable to get a contiguous chunk, OPJ_TRUE otherwise +*/ +OPJ_BOOL opj_seg_buf_zero_copy_read(opj_seg_buf_t* seg_buf, + OPJ_BYTE** ptr, + OPJ_SIZE_T chunk_len) { + opj_buf_t* cur_seg = NULL; + if (!seg_buf) + return OPJ_FALSE; + cur_seg = (opj_buf_t*)opj_vec_get(&seg_buf->segments, seg_buf->cur_seg_id); + if (!cur_seg) + return OPJ_FALSE; + + if ((OPJ_SIZE_T)cur_seg->offset + chunk_len <= cur_seg->len) { + *ptr = cur_seg->buf + cur_seg->offset; + opj_seg_buf_read(seg_buf, NULL, chunk_len); + return OPJ_TRUE; + } + return OPJ_FALSE; +} + +OPJ_BOOL opj_seg_buf_copy_to_contiguous_buffer(opj_seg_buf_t* seg_buf, OPJ_BYTE* buffer) { + OPJ_INT32 i = 0; + OPJ_SIZE_T offset = 0; + + if (!buffer || !seg_buf) + return OPJ_FALSE; + + for (i = 0; i < seg_buf->segments.size; ++i) { + opj_buf_t* seg = (opj_buf_t*)opj_vec_get(&seg_buf->segments, i); + if (seg->len) + memcpy(buffer + offset, seg->buf, seg->len); + offset += seg->len; + } + return OPJ_TRUE; + +} + +OPJ_BYTE* opj_seg_buf_get_global_ptr(opj_seg_buf_t* seg_buf) { + opj_buf_t* cur_seg = NULL; + if (!seg_buf) + return NULL; + cur_seg = (opj_buf_t*)(seg_buf->segments.data[seg_buf->cur_seg_id]); + return (cur_seg) ? (cur_seg->buf + cur_seg->offset) : NULL; +} + +OPJ_SIZE_T opj_seg_buf_get_cur_seg_len(opj_seg_buf_t* seg_buf) { + opj_buf_t* cur_seg = NULL; + if (!seg_buf) + return 0; + cur_seg = (opj_buf_t*)(opj_vec_get(&seg_buf->segments, seg_buf->cur_seg_id)); + return (cur_seg) ? (cur_seg->len - (OPJ_SIZE_T)cur_seg->offset) : 0; +} + +OPJ_OFF_T opj_seg_buf_get_cur_seg_offset(opj_seg_buf_t* seg_buf) { + opj_buf_t* cur_seg = NULL; + if (!seg_buf) + return 0; + cur_seg = (opj_buf_t*)(opj_vec_get(&seg_buf->segments, seg_buf->cur_seg_id)); + return (cur_seg) ? (OPJ_OFF_T)(cur_seg->offset) : 0; +} + + +OPJ_OFF_T opj_seg_buf_get_global_offset(opj_seg_buf_t* seg_buf) { + OPJ_INT32 i = 0; + OPJ_OFF_T offset = 0; + + if (!seg_buf) + return 0; + + for (i = 0; i < seg_buf->cur_seg_id; ++i) { + opj_buf_t* seg = (opj_buf_t*)opj_vec_get(&seg_buf->segments, i); + offset += (OPJ_OFF_T)seg->len; + } + return offset + opj_seg_buf_get_cur_seg_offset(seg_buf); +} + + +void opj_buf_incr_offset(opj_buf_t* buf, OPJ_OFF_T off) { + if (!buf) + return; + /* we allow the offset to move to one location beyond end of buffer segment*/ + if (buf->offset + off > (OPJ_OFF_T)buf->len) { +#ifdef DEBUG_SEG_BUF + printf("Warning: attempt to increment buffer offset out of bounds\n"); +#endif + buf->offset = (OPJ_OFF_T)buf->len; + } + buf->offset += off; +} + +void opj_buf_free(opj_buf_t* buffer) { + if (!buffer) + return; + if (buffer->buf && buffer->owns_data) + opj_free(buffer->buf); + opj_free(buffer); +} + diff --git a/src/lib/openjp2/segmented_stream.h b/src/lib/openjp2/segmented_stream.h new file mode 100644 index 000000000..7e9d851c3 --- /dev/null +++ b/src/lib/openjp2/segmented_stream.h @@ -0,0 +1,155 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2002-2016, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2016, OpenJPEG contributors + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __SEGMENTED_STREAM_H +#define __SEGMENTED_STREAM_H + +/* +Smart wrapper to low level C array +*/ + +typedef struct opj_min_buf { + OPJ_BYTE *buf; /* internal array*/ + OPJ_UINT16 len; /* length of array */ +} opj_min_buf_t; + +/* +Copy all segments, in sequence, into contiguous array +*/ +OPJ_BOOL opj_min_buf_vec_copy_to_contiguous_buffer(opj_vec_t* min_buf_vec, OPJ_BYTE* buffer); + +/* +Push buffer to back of min buf vector +*/ +OPJ_BOOL opj_min_buf_vec_push_back(opj_vec_t* buf_vec, OPJ_BYTE* buf, OPJ_UINT16 len); + +/* +Sum lengths of all buffers +*/ + +OPJ_UINT16 opj_min_buf_vec_get_len(opj_vec_t* min_buf_vec); + +typedef struct opj_buf { + OPJ_BYTE *buf; /* internal array*/ + OPJ_OFF_T offset; /* current offset into array */ + OPJ_SIZE_T len; /* length of array */ + OPJ_BOOL owns_data; /* OPJ_TRUE if buffer manages the buf array */ +} opj_buf_t; + + +/* +Increment buffer offset +*/ +void opj_buf_incr_offset(opj_buf_t* buf, OPJ_OFF_T off); + +/* +Free buffer and also its internal array if owns_data is true +*/ +void opj_buf_free(opj_buf_t* buf); + + +/* Segmented Buffer Interface + +A segmented buffer stores a list of buffers, or segments, but can be treated as one single +contiguous buffer. + +*/ +typedef struct opj_seg_buf +{ + OPJ_SIZE_T data_len; /* total length of all segments*/ + OPJ_INT32 cur_seg_id; /* current index into segments vector */ + opj_vec_t segments; /* vector of segments */ + +} opj_seg_buf_t; + +/* +Wrap existing array and add to the back of the segmented buffer. +*/ +OPJ_BOOL opj_seg_buf_push_back(opj_seg_buf_t* seg_buf, OPJ_BYTE* buf, OPJ_SIZE_T len); + +/* +Allocate array and add to the back of the segmented buffer +*/ +OPJ_BOOL opj_seg_buf_alloc_and_push_back(opj_seg_buf_t* seg_buf, OPJ_SIZE_T len); + +/* +Increment offset of current segment +*/ +void opj_seg_buf_incr_cur_seg_offset(opj_seg_buf_t* seg_buf, OPJ_OFF_T offset); + +/* +Get length of current segment +*/ +OPJ_SIZE_T opj_seg_buf_get_cur_seg_len(opj_seg_buf_t* seg_buf); + +/* +Get offset of current segment +*/ +OPJ_OFF_T opj_seg_buf_get_cur_seg_offset(opj_seg_buf_t* seg_buf); + +/* +Treat segmented buffer as single contiguous buffer, and get current pointer +*/ +OPJ_BYTE* opj_seg_buf_get_global_ptr(opj_seg_buf_t* seg_buf); + +/* +Treat segmented buffer as single contiguous buffer, and get current offset +*/ +OPJ_OFF_T opj_seg_buf_get_global_offset(opj_seg_buf_t* seg_buf); + +/* +Reset all offsets to zero, and set current segment to beginning of list +*/ +void opj_seg_buf_rewind(opj_seg_buf_t* seg_buf); + +/* +Copy all segments, in sequence, into contiguous array +*/ +OPJ_BOOL opj_seg_buf_copy_to_contiguous_buffer(opj_seg_buf_t* seg_buf, OPJ_BYTE* buffer); + +/* +Cleans up internal resources +*/ +void opj_seg_buf_cleanup(opj_seg_buf_t* seg_buf); + +/* +Return current pointer, stored in ptr variable, and advance segmented buffer +offset by chunk_len + +*/ +OPJ_BOOL opj_seg_buf_zero_copy_read(opj_seg_buf_t* seg_buf, + OPJ_BYTE** ptr, + OPJ_SIZE_T chunk_len); + + + +#endif \ No newline at end of file diff --git a/src/lib/openjp2/t1.c b/src/lib/openjp2/t1.c index 108ce78b6..e4b5cfb76 100644 --- a/src/lib/openjp2/t1.c +++ b/src/lib/openjp2/t1.c @@ -39,18 +39,48 @@ #include "opj_includes.h" #include "t1_luts.h" +#ifdef _OPENMP +#include +#endif + /** @defgroup T1 T1 - Implementation of the tier-1 coding */ /*@{*/ /** @name Local static functions */ /*@{*/ + + +typedef OPJ_INT16 opj_flag_t; + +/** +Tier-1 coding (coding of code-block coefficients) +*/ +typedef struct opj_t1 { + OPJ_BYTE* compressed_block; + OPJ_SIZE_T compressed_block_size; + /** MQC component */ + opj_mqc_t *mqc; + /** RAW component */ + opj_raw_t *raw; + + OPJ_INT32 *data; + opj_flag_t *flags; + OPJ_UINT32 w; + OPJ_UINT32 h; + OPJ_UINT32 datasize; + OPJ_UINT32 flagssize; + OPJ_UINT32 flags_stride; + OPJ_UINT32 data_stride; + OPJ_BOOL encoder; +} opj_t1_t; + + + static INLINE OPJ_BYTE opj_t1_getctxno_zc(OPJ_UINT32 f, OPJ_UINT32 orient); static OPJ_BYTE opj_t1_getctxno_sc(OPJ_UINT32 f); static INLINE OPJ_UINT32 opj_t1_getctxno_mag(OPJ_UINT32 f); static OPJ_BYTE opj_t1_getspb(OPJ_UINT32 f); -static OPJ_INT16 opj_t1_getnmsedec_sig(OPJ_UINT32 x, OPJ_UINT32 bitpos); -static OPJ_INT16 opj_t1_getnmsedec_ref(OPJ_UINT32 x, OPJ_UINT32 bitpos); static void opj_t1_updateflags(opj_flag_t *flagsp, OPJ_UINT32 s, OPJ_UINT32 stride); /** Encode significant pass @@ -256,17 +286,6 @@ static void opj_t1_dec_clnpass( OPJ_INT32 orient, OPJ_INT32 cblksty); -static OPJ_FLOAT64 opj_t1_getwmsedec( - OPJ_INT32 nmsedec, - OPJ_UINT32 compno, - OPJ_UINT32 level, - OPJ_UINT32 orient, - OPJ_INT32 bpno, - OPJ_UINT32 qmfbid, - OPJ_FLOAT64 stepsize, - OPJ_UINT32 numcomps, - const OPJ_FLOAT64 * mct_norms, - OPJ_UINT32 mct_numcomps); static void opj_t1_encode_cblk( opj_t1_t *t1, opj_tcd_cblk_enc_t* cblk, @@ -299,6 +318,25 @@ static OPJ_BOOL opj_t1_allocate_buffers( opj_t1_t *t1, OPJ_UINT32 w, OPJ_UINT32 h); + + +/** +* Creates a new Tier 1 handle +* and initializes the look-up tables of the Tier-1 coder/decoder +* @return a new T1 handle if successful, returns NULL otherwise +*/ +opj_t1_t* opj_t1_create(OPJ_BOOL isEncoder, OPJ_UINT16 code_block_width, OPJ_UINT16 code_block_height); + +/** +* Destroys a previously created T1 handle +* +* @param p_t1 Tier 1 handle to destroy +*/ +static void opj_t1_destroy(opj_t1_t *p_t1); + + + + /*@}*/ /*@}*/ @@ -323,7 +361,7 @@ static OPJ_BYTE opj_t1_getspb(OPJ_UINT32 f) { return lut_spb[(f & (T1_SIG_PRIM | T1_SGN)) >> 4]; } -static OPJ_INT16 opj_t1_getnmsedec_sig(OPJ_UINT32 x, OPJ_UINT32 bitpos) { +OPJ_INT16 opj_t1_getnmsedec_sig(OPJ_UINT32 x, OPJ_UINT32 bitpos) { if (bitpos > 0) { return lut_nmsedec_sig[(x >> (bitpos)) & ((1 << T1_NMSEDEC_BITS) - 1)]; } @@ -331,7 +369,7 @@ static OPJ_INT16 opj_t1_getnmsedec_sig(OPJ_UINT32 x, OPJ_UINT32 bitpos) { return lut_nmsedec_sig0[x & ((1 << T1_NMSEDEC_BITS) - 1)]; } -static OPJ_INT16 opj_t1_getnmsedec_ref(OPJ_UINT32 x, OPJ_UINT32 bitpos) { +OPJ_INT16 opj_t1_getnmsedec_ref(OPJ_UINT32 x, OPJ_UINT32 bitpos) { if (bitpos > 0) { return lut_nmsedec_ref[(x >> (bitpos)) & ((1 << T1_NMSEDEC_BITS) - 1)]; } @@ -1130,7 +1168,7 @@ static void opj_t1_dec_clnpass( /** mod fixed_quality */ -static OPJ_FLOAT64 opj_t1_getwmsedec( +OPJ_FLOAT64 opj_t1_getwmsedec( OPJ_INT32 nmsedec, OPJ_UINT32 compno, OPJ_UINT32 level, @@ -1210,7 +1248,7 @@ static OPJ_BOOL opj_t1_allocate_buffers( * and initializes the look-up tables of the Tier-1 coder/decoder * @return a new T1 handle if successful, returns NULL otherwise */ -opj_t1_t* opj_t1_create(OPJ_BOOL isEncoder) +opj_t1_t* opj_t1_create(OPJ_BOOL isEncoder, OPJ_UINT16 code_block_width, OPJ_UINT16 code_block_height) { opj_t1_t *l_t1 = 00; @@ -1231,6 +1269,16 @@ opj_t1_t* opj_t1_create(OPJ_BOOL isEncoder) opj_t1_destroy(l_t1); return 00; } + + if (!isEncoder && code_block_width > 0 && code_block_height > 0) { + l_t1->compressed_block = (OPJ_BYTE*)opj_malloc((OPJ_SIZE_T)code_block_width * (OPJ_SIZE_T)code_block_height); + if (!l_t1->compressed_block) { + opj_t1_destroy(l_t1); + return 00; + } + l_t1->compressed_block_size = (OPJ_SIZE_T)(code_block_width * code_block_height); + + } l_t1->encoder = isEncoder; return l_t1; @@ -1242,7 +1290,7 @@ opj_t1_t* opj_t1_create(OPJ_BOOL isEncoder) * * @param p_t1 Tier 1 handle to destroy */ -void opj_t1_destroy(opj_t1_t *p_t1) +static void opj_t1_destroy(opj_t1_t *p_t1) { if (! p_t1) { return; @@ -1264,18 +1312,18 @@ void opj_t1_destroy(opj_t1_t *p_t1) opj_aligned_free(p_t1->flags); p_t1->flags = 00; } - + if (p_t1->compressed_block) + opj_free(p_t1->compressed_block); opj_free(p_t1); } -OPJ_BOOL opj_t1_decode_cblks( opj_t1_t* t1, - opj_tcd_tilecomp_t* tilec, +OPJ_BOOL opj_t1_decode_cblks( opj_tcd_tilecomp_t* tilec, opj_tccp_t* tccp ) { - OPJ_UINT32 resno, bandno, precno, cblkno; + OPJ_UINT32 resno, bandno, precno; OPJ_UINT32 tile_w = (OPJ_UINT32)(tilec->x1 - tilec->x0); - + OPJ_BOOL rc = OPJ_TRUE; for (resno = 0; resno < tilec->minimum_num_resolutions; ++resno) { opj_tcd_resolution_t* res = &tilec->resolutions[resno]; @@ -1284,21 +1332,35 @@ OPJ_BOOL opj_t1_decode_cblks( opj_t1_t* t1, for (precno = 0; precno < res->pw * res->ph; ++precno) { opj_tcd_precinct_t* precinct = &band->precincts[precno]; + OPJ_INT32 cblkno; - for (cblkno = 0; cblkno < precinct->cw * precinct->ch; ++cblkno) { +#ifdef _OPENMP + #pragma omp parallel default(none) private(cblkno) shared(band, tilec,precinct, tccp, tile_w, resno, rc) + { + #pragma omp for +#endif + for (cblkno = 0; cblkno < (OPJ_INT32)(precinct->cw * precinct->ch); ++cblkno) { opj_tcd_cblk_dec_t* cblk = &precinct->cblks.dec[cblkno]; OPJ_INT32* restrict datap; OPJ_UINT32 cblk_w, cblk_h; OPJ_INT32 x, y; OPJ_UINT32 i, j; - if (OPJ_FALSE == opj_t1_decode_cblk( + opj_t1_t* t1 = opj_t1_create(OPJ_FALSE,(OPJ_UINT16)tccp->cblkw, (OPJ_UINT16)tccp->cblkh); + if (t1 == 00) { + rc = OPJ_FALSE; + continue; + } + + if (!opj_t1_decode_cblk( t1, cblk, band->bandno, (OPJ_UINT32)tccp->roishift, tccp->cblksty)) { - return OPJ_FALSE; + opj_t1_destroy(t1); + rc = OPJ_FALSE; + continue; } x = cblk->x0 - band->x0; @@ -1350,11 +1412,15 @@ OPJ_BOOL opj_t1_decode_cblks( opj_t1_t* t1, tiledp += tile_w; } } + opj_t1_destroy(t1); } /* cblkno */ +#ifdef _OPENMP + } +#endif } /* precno */ } /* bandno */ } /* resno */ - return OPJ_TRUE; + return rc; } @@ -1371,6 +1437,8 @@ static OPJ_BOOL opj_t1_decode_cblk(opj_t1_t *t1, OPJ_UINT32 passtype; OPJ_UINT32 segno, passno; OPJ_BYTE type = T1_TYPE_MQ; /* BYPASS mode */ + OPJ_BYTE* block_buffer = NULL; + OPJ_SIZE_T total_seg_len; if(!opj_t1_allocate_buffers( t1, @@ -1380,6 +1448,33 @@ static OPJ_BOOL opj_t1_decode_cblk(opj_t1_t *t1, return OPJ_FALSE; } + total_seg_len = opj_min_buf_vec_get_len(&cblk->seg_buffers); + if (cblk->real_num_segs && total_seg_len) { + /* if there is only one segment, then it is already contiguous, so no need to make a copy*/ + if (total_seg_len == 1 && cblk->seg_buffers.data[0]) { + block_buffer = ((opj_buf_t*)(cblk->seg_buffers.data[0]))->buf; + } + else { + /* block should have been allocated on creation of t1*/ + if (!t1->compressed_block) + return OPJ_FALSE; + if (t1->compressed_block_size < total_seg_len) { + OPJ_BYTE* new_block = opj_realloc(t1->compressed_block, total_seg_len); + if (!new_block) + return OPJ_FALSE; + t1->compressed_block = new_block; + t1->compressed_block_size = total_seg_len; + } + opj_min_buf_vec_copy_to_contiguous_buffer(&cblk->seg_buffers, t1->compressed_block); + block_buffer = t1->compressed_block; + } + } + else { + return OPJ_TRUE; + } + + + bpno_plus_one = (OPJ_INT32)(roishift + cblk->numbps); passtype = 2; @@ -1393,14 +1488,10 @@ static OPJ_BOOL opj_t1_decode_cblk(opj_t1_t *t1, /* BYPASS mode */ type = ((bpno_plus_one <= ((OPJ_INT32) (cblk->numbps)) - 4) && (passtype < 2) && (cblksty & J2K_CCP_CBLKSTY_LAZY)) ? T1_TYPE_RAW : T1_TYPE_MQ; - /* FIXME: slviewer gets here with a null pointer. Why? Partially downloaded and/or corrupt textures? */ - if(seg->data == 00){ - continue; - } if (type == T1_TYPE_RAW) { - opj_raw_init_dec(raw, (*seg->data) + seg->dataindex, seg->len); + opj_raw_init_dec(raw, block_buffer + seg->dataindex, seg->len); } else { - if (OPJ_FALSE == opj_mqc_init_dec(mqc, (*seg->data) + seg->dataindex, seg->len)) { + if (OPJ_FALSE == opj_mqc_init_dec(mqc, block_buffer + seg->dataindex, seg->len)) { return OPJ_FALSE; } } @@ -1452,17 +1543,29 @@ static OPJ_BOOL opj_t1_decode_cblk(opj_t1_t *t1, -OPJ_BOOL opj_t1_encode_cblks( opj_t1_t *t1, - opj_tcd_tile_t *tile, +OPJ_BOOL opj_t1_encode_cblks( opj_tcd_tile_t *tile, opj_tcp_t *tcp, const OPJ_FLOAT64 * mct_norms, OPJ_UINT32 mct_numcomps ) { - OPJ_UINT32 compno, resno, bandno, precno, cblkno; - + OPJ_BOOL do_opt = OPJ_TRUE; + OPJ_UINT32 compno, resno, bandno, precno; + OPJ_BOOL rc = OPJ_TRUE; tile->distotile = 0; /* fixed_quality */ + for (compno = 0; compno < tile->numcomps; ++compno) { + opj_tccp_t* tccp = tcp->tccps + compno; + if (tccp->cblksty != 0) + { + do_opt = OPJ_FALSE; + break; + } + } + + if (do_opt) + return opj_t1_opt_encode_cblks(tile, tcp, mct_norms, mct_numcomps); + for (compno = 0; compno < tile->numcomps; ++compno) { opj_tcd_tilecomp_t* tilec = &tile->comps[compno]; opj_tccp_t* tccp = &tcp->tccps[compno]; @@ -1477,33 +1580,47 @@ OPJ_BOOL opj_t1_encode_cblks( opj_t1_t *t1, for (precno = 0; precno < res->pw * res->ph; ++precno) { opj_tcd_precinct_t *prc = &band->precincts[precno]; - - for (cblkno = 0; cblkno < prc->cw * prc->ch; ++cblkno) { - opj_tcd_cblk_enc_t* cblk = &prc->cblks.enc[cblkno]; + OPJ_INT32 cblkno; + OPJ_INT32 bandOdd = band->bandno & 1; + OPJ_INT32 bandModTwo = band->bandno & 2; + +#ifdef _OPENMP +#pragma omp parallel default(none) private(cblkno) shared(band, bandOdd, bandModTwo, prc, tilec, tccp, mct_norms, mct_numcomps, bandconst,compno, tile, tile_w, resno, rc) + { + + #pragma omp for +#endif + for (cblkno = 0; cblkno < (OPJ_INT32)(prc->cw * prc->ch); ++cblkno) { OPJ_INT32* restrict tiledp; + opj_tcd_cblk_enc_t* cblk = prc->cblks.enc + cblkno; OPJ_UINT32 cblk_w; OPJ_UINT32 cblk_h; OPJ_UINT32 i, j, tileIndex=0, tileLineAdvance; - + opj_t1_t * t1 = 00; OPJ_INT32 x = cblk->x0 - band->x0; OPJ_INT32 y = cblk->y0 - band->y0; - if (band->bandno & 1) { + if (bandOdd) { opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; x += pres->x1 - pres->x0; } - if (band->bandno & 2) { + if (bandModTwo) { opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; y += pres->y1 - pres->y0; } - + t1 = opj_t1_create(OPJ_TRUE,0,0); + if (!t1) { + rc = OPJ_FALSE; + continue; + } if(!opj_t1_allocate_buffers( t1, (OPJ_UINT32)(cblk->x1 - cblk->x0), (OPJ_UINT32)(cblk->y1 - cblk->y0))) { - return OPJ_FALSE; + opj_t1_destroy(t1); + rc = OPJ_FALSE; + continue; } - cblk_w = t1->w; cblk_h = t1->h; tileLineAdvance = tile_w - cblk_w; @@ -1546,13 +1663,17 @@ OPJ_BOOL opj_t1_encode_cblks( opj_t1_t *t1, tile, mct_norms, mct_numcomps); + opj_t1_destroy(t1); } /* cblkno */ +#ifdef _OPENMP + } +#endif } /* precno */ } /* bandno */ } /* resno */ } /* compno */ - return OPJ_TRUE; + return rc; } /** mod fixed_quality */ diff --git a/src/lib/openjp2/t1.h b/src/lib/openjp2/t1.h index 3bc0ad9ea..c7ec69eef 100644 --- a/src/lib/openjp2/t1.h +++ b/src/lib/openjp2/t1.h @@ -91,28 +91,8 @@ in T1.C are used by some function in TCD.C. /* ----------------------------------------------------------------------- */ -typedef OPJ_INT16 opj_flag_t; -/** -Tier-1 coding (coding of code-block coefficients) -*/ -typedef struct opj_t1 { - - /** MQC component */ - opj_mqc_t *mqc; - /** RAW component */ - opj_raw_t *raw; - - OPJ_INT32 *data; - opj_flag_t *flags; - OPJ_UINT32 w; - OPJ_UINT32 h; - OPJ_UINT32 datasize; - OPJ_UINT32 flagssize; - OPJ_UINT32 flags_stride; - OPJ_UINT32 data_stride; - OPJ_BOOL encoder; -} opj_t1_t; + #define MACRO_t1_flags(x,y) t1->flags[((x)*(t1->flags_stride))+(y)] @@ -128,37 +108,37 @@ Encode the code-blocks of a tile @param mct_norms FIXME DOC @param mct_numcomps Number of components used for MCT */ -OPJ_BOOL opj_t1_encode_cblks( opj_t1_t *t1, - opj_tcd_tile_t *tile, +OPJ_BOOL opj_t1_encode_cblks( opj_tcd_tile_t *tile, opj_tcp_t *tcp, const OPJ_FLOAT64 * mct_norms, OPJ_UINT32 mct_numcomps); /** Decode the code-blocks of a tile -@param t1 T1 handle @param tilec The tile to decode @param tccp Tile coding parameters */ -OPJ_BOOL opj_t1_decode_cblks( opj_t1_t* t1, - opj_tcd_tilecomp_t* tilec, +OPJ_BOOL opj_t1_decode_cblks( opj_tcd_tilecomp_t* tilec, opj_tccp_t* tccp); +OPJ_FLOAT64 opj_t1_getwmsedec( + OPJ_INT32 nmsedec, + OPJ_UINT32 compno, + OPJ_UINT32 level, + OPJ_UINT32 orient, + OPJ_INT32 bpno, + OPJ_UINT32 qmfbid, + OPJ_FLOAT64 stepsize, + OPJ_UINT32 numcomps, + const OPJ_FLOAT64 * mct_norms, + OPJ_UINT32 mct_numcomps); + + +OPJ_INT16 opj_t1_getnmsedec_sig(OPJ_UINT32 x, OPJ_UINT32 bitpos); +OPJ_INT16 opj_t1_getnmsedec_ref(OPJ_UINT32 x, OPJ_UINT32 bitpos); -/** - * Creates a new Tier 1 handle - * and initializes the look-up tables of the Tier-1 coder/decoder - * @return a new T1 handle if successful, returns NULL otherwise -*/ -opj_t1_t* opj_t1_create(OPJ_BOOL isEncoder); -/** - * Destroys a previously created T1 handle - * - * @param p_t1 Tier 1 handle to destroy -*/ -void opj_t1_destroy(opj_t1_t *p_t1); /* ----------------------------------------------------------------------- */ /*@}*/ diff --git a/src/lib/openjp2/t1_generate_luts.c b/src/lib/openjp2/t1_generate_luts.c index 1997d3997..d8dab2a88 100644 --- a/src/lib/openjp2/t1_generate_luts.c +++ b/src/lib/openjp2/t1_generate_luts.c @@ -110,6 +110,91 @@ static int t1_init_ctxno_zc(int f, int orient) { return (T1_CTXNO_ZC + n); } +static int t1_init_ctxno_zc_opt(int f, int orient) { + int h, v, d, n, t, hv; + n = 0; + h = ((f & T1_SIGMA_3) != 0) + ((f & T1_SIGMA_5) != 0); + v = ((f & T1_SIGMA_1) != 0) + ((f & T1_SIGMA_7) != 0); + d = ((f & T1_SIGMA_0) != 0) + ((f & T1_SIGMA_2) != 0) + ((f & T1_SIGMA_8) != 0) + ((f & T1_SIGMA_6) != 0); + + switch (orient) { + case 2: + t = h; + h = v; + v = t; + case 0: + case 1: + if (!h) { + if (!v) { + if (!d) + n = 0; + else if (d == 1) + n = 1; + else + n = 2; + } + else if (v == 1) { + n = 3; + } + else { + n = 4; + } + } + else if (h == 1) { + if (!v) { + if (!d) + n = 5; + else + n = 6; + } + else { + n = 7; + } + } + else + n = 8; + break; + case 3: + hv = h + v; + if (!d) { + if (!hv) { + n = 0; + } + else if (hv == 1) { + n = 1; + } + else { + n = 2; + } + } + else if (d == 1) { + if (!hv) { + n = 3; + } + else if (hv == 1) { + n = 4; + } + else { + n = 5; + } + } + else if (d == 2) { + if (!hv) { + n = 6; + } + else { + n = 7; + } + } + else { + n = 8; + } + break; + } + + return (T1_CTXNO_ZC + n); +} + static int t1_init_ctxno_sc(int f) { int hc, vc, n; n = 0; @@ -151,6 +236,49 @@ static int t1_init_ctxno_sc(int f) { return (T1_CTXNO_SC + n); } + +static int t1_init_ctxno_sc_opt(int f) { + int hc, vc, n; + n = 0; + + hc = opj_int_min(((f & (T1_LUT_SIG_E | T1_LUT_SGN_E)) == + T1_LUT_SIG_E) + ((f & (T1_LUT_SIG_W | T1_LUT_SGN_W)) == T1_LUT_SIG_W), + 1) - opj_int_min(((f & (T1_LUT_SIG_E | T1_LUT_SGN_E)) == + (T1_LUT_SIG_E | T1_LUT_SGN_E)) + + ((f & (T1_LUT_SIG_W | T1_LUT_SGN_W)) == + (T1_LUT_SIG_W | T1_LUT_SGN_W)), 1); + + vc = opj_int_min(((f & (T1_LUT_SIG_N | T1_LUT_SGN_N)) == + T1_LUT_SIG_N) + ((f & (T1_LUT_SIG_S | T1_LUT_SGN_S)) == T1_LUT_SIG_S), + 1) - opj_int_min(((f & (T1_LUT_SIG_N | T1_LUT_SGN_N)) == + (T1_LUT_SIG_N | T1_LUT_SGN_N)) + + ((f & (T1_LUT_SIG_S | T1_LUT_SGN_S)) == + (T1_LUT_SIG_S | T1_LUT_SGN_S)), 1); + + if (hc < 0) { + hc = -hc; + vc = -vc; + } + if (!hc) { + if (vc == -1) + n = 1; + else if (!vc) + n = 0; + else + n = 1; + } + else if (hc == 1) { + if (vc == -1) + n = 2; + else if (!vc) + n = 3; + else + n = 4; + } + + return (T1_CTXNO_SC + n); +} + static int t1_init_spb(int f) { int hc, vc, n; @@ -176,6 +304,32 @@ static int t1_init_spb(int f) { return n; } + +static int t1_init_spb_opt(int f) { + int hc, vc, n; + + hc = opj_int_min(((f & (T1_LUT_SIG_E | T1_LUT_SGN_E)) == + T1_LUT_SIG_E) + ((f & (T1_LUT_SIG_W | T1_LUT_SGN_W)) == T1_LUT_SIG_W), + 1) - opj_int_min(((f & (T1_LUT_SIG_E | T1_LUT_SGN_E)) == + (T1_LUT_SIG_E | T1_LUT_SGN_E)) + + ((f & (T1_LUT_SIG_W | T1_LUT_SGN_W)) == + (T1_LUT_SIG_W | T1_LUT_SGN_W)), 1); + + vc = opj_int_min(((f & (T1_LUT_SIG_N | T1_LUT_SGN_N)) == + T1_LUT_SIG_N) + ((f & (T1_LUT_SIG_S | T1_LUT_SGN_S)) == T1_LUT_SIG_S), + 1) - opj_int_min(((f & (T1_LUT_SIG_N | T1_LUT_SGN_N)) == + (T1_LUT_SIG_N | T1_LUT_SGN_N)) + + ((f & (T1_LUT_SIG_S | T1_LUT_SGN_S)) == + (T1_LUT_SIG_S | T1_LUT_SGN_S)), 1); + + if (!hc && !vc) + n = 0; + else + n = (!(hc > 0 || (!hc && vc > 0))); + + return n; +} + static void dump_array16(int array[],int size){ int i; --size; @@ -193,6 +347,7 @@ int main(int argc, char **argv) double u, v, t; int lut_ctxno_zc[1024]; + int lut_ctxno_zc_opt[2048]; int lut_nmsedec_sig[1 << T1_NMSEDEC_BITS]; int lut_nmsedec_sig0[1 << T1_NMSEDEC_BITS]; int lut_nmsedec_ref[1 << T1_NMSEDEC_BITS]; @@ -222,6 +377,28 @@ int main(int argc, char **argv) } printf("%i\n};\n\n", lut_ctxno_zc[1023]); + /* lut_ctxno_zc_opt */ + for (j = 0; j < 4; ++j) { + for (i = 0; i < 512; ++i) { + int orient = j; + if (orient == 2) { + orient = 1; + } + else if (orient == 1) { + orient = 2; + } + lut_ctxno_zc_opt[(orient << 9) | i] = t1_init_ctxno_zc_opt(i, j); + } + } + + printf("static OPJ_BYTE lut_ctxno_zc_opt[2048] = {\n "); + for (i = 0; i < 2047; ++i) { + printf("%i, ", lut_ctxno_zc_opt[i]); + if (!((i + 1) & 0x1f)) + printf("\n "); + } + printf("%i\n};\n\n", lut_ctxno_zc_opt[2047]); + /* lut_ctxno_sc */ printf("static OPJ_BYTE lut_ctxno_sc[256] = {\n "); for (i = 0; i < 255; ++i) { @@ -231,6 +408,17 @@ int main(int argc, char **argv) } printf("0x%x\n};\n\n", t1_init_ctxno_sc(255 << 4)); + + /* lut_ctxno_sc_opt */ + printf("static OPJ_BYTE lut_ctxno_sc_opt[256] = {\n "); + for (i = 0; i < 255; ++i) { + printf("0x%x, ", t1_init_ctxno_sc_opt(i)); + if (!((i + 1) & 0xf)) + printf("\n "); + } + printf("0x%x\n};\n\n", t1_init_ctxno_sc_opt(255)); + + /* lut_spb */ printf("static OPJ_BYTE lut_spb[256] = {\n "); for (i = 0; i < 255; ++i) { @@ -240,6 +428,16 @@ int main(int argc, char **argv) } printf("%i\n};\n\n", t1_init_spb(255 << 4)); + + /* lut_spb_opt */ + printf("static OPJ_BYTE lut_spb_opt[256] = {\n "); + for (i = 0; i < 255; ++i) { + printf("%i, ", t1_init_spb_opt(i)); + if (!((i + 1) & 0x1f)) + printf("\n "); + } + printf("%i\n};\n\n", t1_init_spb_opt(255)); + /* FIXME FIXME FIXME */ /* fprintf(stdout,"nmsedec luts:\n"); */ for (i = 0; i < (1 << T1_NMSEDEC_BITS); ++i) { diff --git a/src/lib/openjp2/t1_luts.h b/src/lib/openjp2/t1_luts.h index 37776b65a..b80cdac3f 100644 --- a/src/lib/openjp2/t1_luts.h +++ b/src/lib/openjp2/t1_luts.h @@ -35,6 +35,74 @@ static OPJ_BYTE lut_ctxno_zc[1024] = { 2, 5, 5, 7, 5, 7, 7, 8, 5, 7, 7, 8, 7, 8, 8, 8, 2, 5, 5, 7, 5, 7, 7, 8, 5, 7, 7, 8, 7, 8, 8, 8 }; + +static OPJ_BYTE lut_ctxno_zc_opt[2048] = { + 0, 1, 3, 3, 1, 2, 3, 3, 5, 6, 7, 7, 6, 6, 7, 7, 0, 1, 3, 3, 1, 2, 3, 3, 5, 6, 7, 7, 6, 6, 7, 7, + 5, 6, 7, 7, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 5, 6, 7, 7, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, + 1, 2, 3, 3, 2, 2, 3, 3, 6, 6, 7, 7, 6, 6, 7, 7, 1, 2, 3, 3, 2, 2, 3, 3, 6, 6, 7, 7, 6, 6, 7, 7, + 6, 6, 7, 7, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 6, 6, 7, 7, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, + 3, 3, 4, 4, 3, 3, 4, 4, 7, 7, 7, 7, 7, 7, 7, 7, 3, 3, 4, 4, 3, 3, 4, 4, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, + 3, 3, 4, 4, 3, 3, 4, 4, 7, 7, 7, 7, 7, 7, 7, 7, 3, 3, 4, 4, 3, 3, 4, 4, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, + 1, 2, 3, 3, 2, 2, 3, 3, 6, 6, 7, 7, 6, 6, 7, 7, 1, 2, 3, 3, 2, 2, 3, 3, 6, 6, 7, 7, 6, 6, 7, 7, + 6, 6, 7, 7, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 6, 6, 7, 7, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, + 2, 2, 3, 3, 2, 2, 3, 3, 6, 6, 7, 7, 6, 6, 7, 7, 2, 2, 3, 3, 2, 2, 3, 3, 6, 6, 7, 7, 6, 6, 7, 7, + 6, 6, 7, 7, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 6, 6, 7, 7, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, + 3, 3, 4, 4, 3, 3, 4, 4, 7, 7, 7, 7, 7, 7, 7, 7, 3, 3, 4, 4, 3, 3, 4, 4, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, + 3, 3, 4, 4, 3, 3, 4, 4, 7, 7, 7, 7, 7, 7, 7, 7, 3, 3, 4, 4, 3, 3, 4, 4, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, + 0, 1, 5, 6, 1, 2, 6, 6, 3, 3, 7, 7, 3, 3, 7, 7, 0, 1, 5, 6, 1, 2, 6, 6, 3, 3, 7, 7, 3, 3, 7, 7, + 3, 3, 7, 7, 3, 3, 7, 7, 4, 4, 7, 7, 4, 4, 7, 7, 3, 3, 7, 7, 3, 3, 7, 7, 4, 4, 7, 7, 4, 4, 7, 7, + 1, 2, 6, 6, 2, 2, 6, 6, 3, 3, 7, 7, 3, 3, 7, 7, 1, 2, 6, 6, 2, 2, 6, 6, 3, 3, 7, 7, 3, 3, 7, 7, + 3, 3, 7, 7, 3, 3, 7, 7, 4, 4, 7, 7, 4, 4, 7, 7, 3, 3, 7, 7, 3, 3, 7, 7, 4, 4, 7, 7, 4, 4, 7, 7, + 5, 6, 8, 8, 6, 6, 8, 8, 7, 7, 8, 8, 7, 7, 8, 8, 5, 6, 8, 8, 6, 6, 8, 8, 7, 7, 8, 8, 7, 7, 8, 8, + 7, 7, 8, 8, 7, 7, 8, 8, 7, 7, 8, 8, 7, 7, 8, 8, 7, 7, 8, 8, 7, 7, 8, 8, 7, 7, 8, 8, 7, 7, 8, 8, + 6, 6, 8, 8, 6, 6, 8, 8, 7, 7, 8, 8, 7, 7, 8, 8, 6, 6, 8, 8, 6, 6, 8, 8, 7, 7, 8, 8, 7, 7, 8, 8, + 7, 7, 8, 8, 7, 7, 8, 8, 7, 7, 8, 8, 7, 7, 8, 8, 7, 7, 8, 8, 7, 7, 8, 8, 7, 7, 8, 8, 7, 7, 8, 8, + 1, 2, 6, 6, 2, 2, 6, 6, 3, 3, 7, 7, 3, 3, 7, 7, 1, 2, 6, 6, 2, 2, 6, 6, 3, 3, 7, 7, 3, 3, 7, 7, + 3, 3, 7, 7, 3, 3, 7, 7, 4, 4, 7, 7, 4, 4, 7, 7, 3, 3, 7, 7, 3, 3, 7, 7, 4, 4, 7, 7, 4, 4, 7, 7, + 2, 2, 6, 6, 2, 2, 6, 6, 3, 3, 7, 7, 3, 3, 7, 7, 2, 2, 6, 6, 2, 2, 6, 6, 3, 3, 7, 7, 3, 3, 7, 7, + 3, 3, 7, 7, 3, 3, 7, 7, 4, 4, 7, 7, 4, 4, 7, 7, 3, 3, 7, 7, 3, 3, 7, 7, 4, 4, 7, 7, 4, 4, 7, 7, + 6, 6, 8, 8, 6, 6, 8, 8, 7, 7, 8, 8, 7, 7, 8, 8, 6, 6, 8, 8, 6, 6, 8, 8, 7, 7, 8, 8, 7, 7, 8, 8, + 7, 7, 8, 8, 7, 7, 8, 8, 7, 7, 8, 8, 7, 7, 8, 8, 7, 7, 8, 8, 7, 7, 8, 8, 7, 7, 8, 8, 7, 7, 8, 8, + 6, 6, 8, 8, 6, 6, 8, 8, 7, 7, 8, 8, 7, 7, 8, 8, 6, 6, 8, 8, 6, 6, 8, 8, 7, 7, 8, 8, 7, 7, 8, 8, + 7, 7, 8, 8, 7, 7, 8, 8, 7, 7, 8, 8, 7, 7, 8, 8, 7, 7, 8, 8, 7, 7, 8, 8, 7, 7, 8, 8, 7, 7, 8, 8, + 0, 1, 3, 3, 1, 2, 3, 3, 5, 6, 7, 7, 6, 6, 7, 7, 0, 1, 3, 3, 1, 2, 3, 3, 5, 6, 7, 7, 6, 6, 7, 7, + 5, 6, 7, 7, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 5, 6, 7, 7, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, + 1, 2, 3, 3, 2, 2, 3, 3, 6, 6, 7, 7, 6, 6, 7, 7, 1, 2, 3, 3, 2, 2, 3, 3, 6, 6, 7, 7, 6, 6, 7, 7, + 6, 6, 7, 7, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 6, 6, 7, 7, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, + 3, 3, 4, 4, 3, 3, 4, 4, 7, 7, 7, 7, 7, 7, 7, 7, 3, 3, 4, 4, 3, 3, 4, 4, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, + 3, 3, 4, 4, 3, 3, 4, 4, 7, 7, 7, 7, 7, 7, 7, 7, 3, 3, 4, 4, 3, 3, 4, 4, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, + 1, 2, 3, 3, 2, 2, 3, 3, 6, 6, 7, 7, 6, 6, 7, 7, 1, 2, 3, 3, 2, 2, 3, 3, 6, 6, 7, 7, 6, 6, 7, 7, + 6, 6, 7, 7, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 6, 6, 7, 7, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, + 2, 2, 3, 3, 2, 2, 3, 3, 6, 6, 7, 7, 6, 6, 7, 7, 2, 2, 3, 3, 2, 2, 3, 3, 6, 6, 7, 7, 6, 6, 7, 7, + 6, 6, 7, 7, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 6, 6, 7, 7, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, + 3, 3, 4, 4, 3, 3, 4, 4, 7, 7, 7, 7, 7, 7, 7, 7, 3, 3, 4, 4, 3, 3, 4, 4, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, + 3, 3, 4, 4, 3, 3, 4, 4, 7, 7, 7, 7, 7, 7, 7, 7, 3, 3, 4, 4, 3, 3, 4, 4, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, + 0, 3, 1, 4, 3, 6, 4, 7, 1, 4, 2, 5, 4, 7, 5, 7, 0, 3, 1, 4, 3, 6, 4, 7, 1, 4, 2, 5, 4, 7, 5, 7, + 1, 4, 2, 5, 4, 7, 5, 7, 2, 5, 2, 5, 5, 7, 5, 7, 1, 4, 2, 5, 4, 7, 5, 7, 2, 5, 2, 5, 5, 7, 5, 7, + 3, 6, 4, 7, 6, 8, 7, 8, 4, 7, 5, 7, 7, 8, 7, 8, 3, 6, 4, 7, 6, 8, 7, 8, 4, 7, 5, 7, 7, 8, 7, 8, + 4, 7, 5, 7, 7, 8, 7, 8, 5, 7, 5, 7, 7, 8, 7, 8, 4, 7, 5, 7, 7, 8, 7, 8, 5, 7, 5, 7, 7, 8, 7, 8, + 1, 4, 2, 5, 4, 7, 5, 7, 2, 5, 2, 5, 5, 7, 5, 7, 1, 4, 2, 5, 4, 7, 5, 7, 2, 5, 2, 5, 5, 7, 5, 7, + 2, 5, 2, 5, 5, 7, 5, 7, 2, 5, 2, 5, 5, 7, 5, 7, 2, 5, 2, 5, 5, 7, 5, 7, 2, 5, 2, 5, 5, 7, 5, 7, + 4, 7, 5, 7, 7, 8, 7, 8, 5, 7, 5, 7, 7, 8, 7, 8, 4, 7, 5, 7, 7, 8, 7, 8, 5, 7, 5, 7, 7, 8, 7, 8, + 5, 7, 5, 7, 7, 8, 7, 8, 5, 7, 5, 7, 7, 8, 7, 8, 5, 7, 5, 7, 7, 8, 7, 8, 5, 7, 5, 7, 7, 8, 7, 8, + 3, 6, 4, 7, 6, 8, 7, 8, 4, 7, 5, 7, 7, 8, 7, 8, 3, 6, 4, 7, 6, 8, 7, 8, 4, 7, 5, 7, 7, 8, 7, 8, + 4, 7, 5, 7, 7, 8, 7, 8, 5, 7, 5, 7, 7, 8, 7, 8, 4, 7, 5, 7, 7, 8, 7, 8, 5, 7, 5, 7, 7, 8, 7, 8, + 6, 8, 7, 8, 8, 8, 8, 8, 7, 8, 7, 8, 8, 8, 8, 8, 6, 8, 7, 8, 8, 8, 8, 8, 7, 8, 7, 8, 8, 8, 8, 8, + 7, 8, 7, 8, 8, 8, 8, 8, 7, 8, 7, 8, 8, 8, 8, 8, 7, 8, 7, 8, 8, 8, 8, 8, 7, 8, 7, 8, 8, 8, 8, 8, + 4, 7, 5, 7, 7, 8, 7, 8, 5, 7, 5, 7, 7, 8, 7, 8, 4, 7, 5, 7, 7, 8, 7, 8, 5, 7, 5, 7, 7, 8, 7, 8, + 5, 7, 5, 7, 7, 8, 7, 8, 5, 7, 5, 7, 7, 8, 7, 8, 5, 7, 5, 7, 7, 8, 7, 8, 5, 7, 5, 7, 7, 8, 7, 8, + 7, 8, 7, 8, 8, 8, 8, 8, 7, 8, 7, 8, 8, 8, 8, 8, 7, 8, 7, 8, 8, 8, 8, 8, 7, 8, 7, 8, 8, 8, 8, 8, + 7, 8, 7, 8, 8, 8, 8, 8, 7, 8, 7, 8, 8, 8, 8, 8, 7, 8, 7, 8, 8, 8, 8, 8, 7, 8, 7, 8, 8, 8, 8, 8 +}; + static OPJ_BYTE lut_ctxno_sc[256] = { 0x9, 0xa, 0xc, 0xd, 0xa, 0xa, 0xd, 0xd, 0xc, 0xd, 0xc, 0xd, 0xd, 0xd, 0xd, 0xd, 0x9, 0xa, 0xc, 0xb, 0xa, 0x9, 0xd, 0xc, 0xc, 0xb, 0xc, 0xb, 0xd, 0xc, 0xd, 0xc, @@ -54,6 +122,28 @@ static OPJ_BYTE lut_ctxno_sc[256] = { 0x9, 0xa, 0xc, 0xd, 0xa, 0xa, 0xd, 0xd, 0xc, 0xd, 0xc, 0xd, 0xd, 0xd, 0xd, 0xd }; + +static OPJ_BYTE lut_ctxno_sc_opt[256] = { + 0x9, 0x9, 0xa, 0xa, 0x9, 0x9, 0xa, 0xa, 0xc, 0xc, 0xd, 0xb, 0xc, 0xc, 0xd, 0xb, + 0x9, 0x9, 0xa, 0xa, 0x9, 0x9, 0xa, 0xa, 0xc, 0xc, 0xb, 0xd, 0xc, 0xc, 0xb, 0xd, + 0xc, 0xc, 0xd, 0xd, 0xc, 0xc, 0xb, 0xb, 0xc, 0x9, 0xd, 0xa, 0x9, 0xc, 0xa, 0xb, + 0xc, 0xc, 0xb, 0xb, 0xc, 0xc, 0xd, 0xd, 0xc, 0x9, 0xb, 0xa, 0x9, 0xc, 0xa, 0xd, + 0x9, 0x9, 0xa, 0xa, 0x9, 0x9, 0xa, 0xa, 0xc, 0xc, 0xd, 0xb, 0xc, 0xc, 0xd, 0xb, + 0x9, 0x9, 0xa, 0xa, 0x9, 0x9, 0xa, 0xa, 0xc, 0xc, 0xb, 0xd, 0xc, 0xc, 0xb, 0xd, + 0xc, 0xc, 0xd, 0xd, 0xc, 0xc, 0xb, 0xb, 0xc, 0x9, 0xd, 0xa, 0x9, 0xc, 0xa, 0xb, + 0xc, 0xc, 0xb, 0xb, 0xc, 0xc, 0xd, 0xd, 0xc, 0x9, 0xb, 0xa, 0x9, 0xc, 0xa, 0xd, + 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xd, 0xb, 0xd, 0xb, 0xd, 0xb, 0xd, 0xb, + 0xa, 0xa, 0x9, 0x9, 0xa, 0xa, 0x9, 0x9, 0xd, 0xb, 0xc, 0xc, 0xd, 0xb, 0xc, 0xc, + 0xd, 0xd, 0xd, 0xd, 0xb, 0xb, 0xb, 0xb, 0xd, 0xa, 0xd, 0xa, 0xa, 0xb, 0xa, 0xb, + 0xd, 0xd, 0xc, 0xc, 0xb, 0xb, 0xc, 0xc, 0xd, 0xa, 0xc, 0x9, 0xa, 0xb, 0x9, 0xc, + 0xa, 0xa, 0x9, 0x9, 0xa, 0xa, 0x9, 0x9, 0xb, 0xd, 0xc, 0xc, 0xb, 0xd, 0xc, 0xc, + 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xb, 0xd, 0xb, 0xd, 0xb, 0xd, 0xb, 0xd, + 0xb, 0xb, 0xc, 0xc, 0xd, 0xd, 0xc, 0xc, 0xb, 0xa, 0xc, 0x9, 0xa, 0xd, 0x9, 0xc, + 0xb, 0xb, 0xb, 0xb, 0xd, 0xd, 0xd, 0xd, 0xb, 0xa, 0xb, 0xa, 0xa, 0xd, 0xa, 0xd +}; + + + static OPJ_BYTE lut_spb[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, @@ -65,6 +155,20 @@ static OPJ_BYTE lut_spb[256] = { 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; + + +static OPJ_BYTE lut_spb_opt[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, + 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, + 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, + 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, + 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, + 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1 +}; + + static OPJ_INT16 lut_nmsedec_sig[1 << T1_NMSEDEC_BITS] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, diff --git a/src/lib/openjp2/t1_opt.c b/src/lib/openjp2/t1_opt.c new file mode 100644 index 000000000..8568b94f5 --- /dev/null +++ b/src/lib/openjp2/t1_opt.c @@ -0,0 +1,891 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux + * Copyright (c) 2003-2014, Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2007, Callum Lerwick + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opj_includes.h" +#include "t1_luts.h" + +#ifdef _OPENMP +#include +#endif + + +/** @defgroup T1 T1 - Implementation of the tier-1 coding */ +/*@{*/ + +/** @name Local static functions */ +/*@{*/ + + +typedef OPJ_UINT32 opj_flag_opt_t; + +/** +Tier-1 coding (coding of code-block coefficients) +*/ +typedef struct opj_t1_opt { + opj_mqc_t *mqc; + OPJ_UINT32 *data; + opj_flag_opt_t *flags; + OPJ_UINT32 w; + OPJ_UINT32 h; + OPJ_UINT32 datasize; + OPJ_UINT32 flagssize; + OPJ_UINT32 flags_stride; + OPJ_BOOL encoder; +} opj_t1_opt_t; + + + + +#define ENC_FLAGS(x, y) (t1->flags[(x) + 1 + (((y) >> 2) + 1) * t1->flags_stride]) +#define ENC_FLAGS_ADDRESS(x, y) (t1->flags + ((x) + 1 + (((y) >> 2) + 1) * t1->flags_stride)) + +static INLINE OPJ_BYTE opj_t1_getctxno_zc_opt(OPJ_UINT32 f, OPJ_UINT32 orient); +static INLINE OPJ_BYTE opj_t1_getctxno_sc_opt(OPJ_UINT32 fX, OPJ_UINT32 pfX, OPJ_UINT32 nfX, OPJ_UINT32 ci); +static INLINE OPJ_UINT32 opj_t1_getctxno_mag_opt(OPJ_UINT32 f); +static INLINE OPJ_BYTE opj_t1_getspb_opt(OPJ_UINT32 fX, OPJ_UINT32 pfX, OPJ_UINT32 nfX, OPJ_UINT32 ci); +static INLINE void opj_t1_updateflags_opt(opj_flag_opt_t *flagsp, OPJ_UINT32 ci, OPJ_UINT32 s, OPJ_UINT32 stride); + +/** +Encode significant pass +*/ +static void opj_t1_enc_sigpass_step(opj_t1_opt_t *t1, + opj_flag_opt_t *flagsp, + OPJ_UINT32 *datap, + OPJ_UINT32 orient, + OPJ_INT32 bpno, + OPJ_INT32 one, + OPJ_INT32 *nmsedec); + +/** +Encode significant pass +*/ +static void opj_t1_enc_sigpass( opj_t1_opt_t *t1, + OPJ_INT32 bpno, + OPJ_UINT32 orient, + OPJ_INT32 *nmsedec); + + +/** +Encode refinement pass +*/ +static void opj_t1_enc_refpass_step(opj_t1_opt_t *t1, + opj_flag_opt_t *flagsp, + OPJ_UINT32 *datap, + OPJ_INT32 bpno, + OPJ_INT32 one, + OPJ_INT32 *nmsedec); + + +/** +Encode refinement pass +*/ +static void opj_t1_enc_refpass( opj_t1_opt_t *t1, + OPJ_INT32 bpno, + OPJ_INT32 *nmsedec); + + + +/** +Encode clean-up pass +*/ +static void opj_t1_enc_clnpass_step( + opj_t1_opt_t *t1, + opj_flag_opt_t *flagsp, + OPJ_UINT32 *datap, + OPJ_UINT32 orient, + OPJ_INT32 bpno, + OPJ_INT32 one, + OPJ_INT32 *nmsedec, + OPJ_UINT32 agg, + OPJ_UINT32 runlen, + OPJ_UINT32 y); + +/** +Encode clean-up pass +*/ +static void opj_t1_enc_clnpass( + opj_t1_opt_t *t1, + OPJ_INT32 bpno, + OPJ_UINT32 orient, + OPJ_INT32 *nmsedec); + + +static void opj_t1_encode_cblk(opj_t1_opt_t *t1, + opj_tcd_cblk_enc_t* cblk, + OPJ_UINT32 orient, + OPJ_UINT32 compno, + OPJ_UINT32 level, + OPJ_UINT32 qmfbid, + OPJ_FLOAT64 stepsize, + OPJ_UINT32 numcomps, + opj_tcd_tile_t * tile, + const OPJ_FLOAT64 * mct_norms, + OPJ_UINT32 mct_numcomps, + OPJ_UINT32 max); + + +static OPJ_BOOL opj_t1_allocate_buffers( opj_t1_opt_t *t1, + OPJ_UINT32 w, + OPJ_UINT32 h); + + + +/** +* Creates a new Tier 1 handle +* and initializes the look-up tables of the Tier-1 coder/decoder +* @return a new T1 handle if successful, returns NULL otherwise +*/ +static opj_t1_opt_t* opj_t1_create(OPJ_BOOL isEncoder); + +/** +* Destroys a previously created T1 handle +* +* @param p_t1 Tier 1 handle to destroy +*/ +static void opj_t1_destroy(opj_t1_opt_t *p_t1); + + + +/** +* Creates a new Tier 1 handle +* and initializes the look-up tables of the Tier-1 coder/decoder +* @return a new T1 handle if successful, returns NULL otherwise +*/ +static opj_t1_opt_t* opj_t1_create(OPJ_BOOL isEncoder) +{ + opj_t1_opt_t *l_t1 = 00; + + l_t1 = (opj_t1_opt_t*)opj_calloc(1, sizeof(opj_t1_opt_t)); + if (!l_t1) { + return 00; + } + + /* create MQC handles */ + l_t1->mqc = opj_mqc_create(); + if (!l_t1->mqc) { + opj_t1_destroy(l_t1); + return 00; + } + + l_t1->encoder = isEncoder; + + return l_t1; +} + + +/** +* Destroys a previously created T1 handle +* +* @param p_t1 Tier 1 handle to destroy +*/ +static void opj_t1_destroy(opj_t1_opt_t *p_t1) +{ + if (!p_t1) { + return; + } + + /* destroy MQC handles */ + opj_mqc_destroy(p_t1->mqc); + p_t1->mqc = 00; + + /* encoder uses tile buffer, so no need to free */ + if (p_t1->data) { + opj_aligned_free(p_t1->data); + p_t1->data = 00; + } + + if (p_t1->flags) { + opj_aligned_free(p_t1->flags); + p_t1->flags = 00; + } + + opj_free(p_t1); +} + +static INLINE OPJ_BYTE opj_t1_getctxno_zc_opt(OPJ_UINT32 f, OPJ_UINT32 orient) { + return lut_ctxno_zc_opt[(orient << 9) | (f & T1_SIGMA_NEIGHBOURS)]; +} + + +static OPJ_BYTE opj_t1_getctxno_sc_opt(OPJ_UINT32 fX, OPJ_UINT32 pfX, OPJ_UINT32 nfX, OPJ_UINT32 ci) { + /* + 0 pfX T1_CHI_THIS T1_LUT_CTXNO_SGN_W + 1 tfX T1_SIGMA_1 T1_LUT_CTXNO_SIG_N + 2 nfX T1_CHI_THIS T1_LUT_CTXNO_SGN_E + 3 tfX T1_SIGMA_3 T1_LUT_CTXNO_SIG_W + 4 fX T1_CHI_(THIS - 1) T1_LUT_CTXNO_SGN_N + 5 tfX T1_SIGMA_5 T1_LUT_CTXNO_SIG_E + 6 fX T1_CHI_(THIS + 1) T1_LUT_CTXNO_SGN_S + 7 tfX T1_SIGMA_7 T1_LUT_CTXNO_SIG_S + */ + + OPJ_UINT32 lu = (fX >> (ci * 3)) & (T1_SIGMA_1 | T1_SIGMA_3 | T1_SIGMA_5 | T1_SIGMA_7); + + lu |= (pfX >> (T1_CHI_THIS_I + (ci * 3U))) & (1U << 0); + lu |= (nfX >> (T1_CHI_THIS_I - 2U + (ci * 3U))) & (1U << 2); + if (ci == 0U) { + lu |= (fX >> (T1_CHI_0_I - 4U)) & (1U << 4); + } + else { + lu |= (fX >> (T1_CHI_1_I - 4U + ((ci - 1U) * 3U))) & (1U << 4); + } + lu |= (fX >> (T1_CHI_2_I - 6U + (ci * 3U))) & (1U << 6); + + return lut_ctxno_sc_opt[lu]; +} + + +static INLINE OPJ_UINT32 opj_t1_getctxno_mag_opt(OPJ_UINT32 f) { + return (f & T1_MU_THIS) ? (T1_CTXNO_MAG + 2) : ((f & T1_SIGMA_NEIGHBOURS) ? T1_CTXNO_MAG + 1 : T1_CTXNO_MAG); +} + +static OPJ_BYTE opj_t1_getspb_opt(OPJ_UINT32 fX, OPJ_UINT32 pfX, OPJ_UINT32 nfX, OPJ_UINT32 ci) { + /* + 0 pfX T1_CHI_THIS T1_LUT_SGN_W + 1 tfX T1_SIGMA_1 T1_LUT_SIG_N + 2 nfX T1_CHI_THIS T1_LUT_SGN_E + 3 tfX T1_SIGMA_3 T1_LUT_SIG_W + 4 fX T1_CHI_(THIS - 1) T1_LUT_SGN_N + 5 tfX T1_SIGMA_5 T1_LUT_SIG_E + 6 fX T1_CHI_(THIS + 1) T1_LUT_SGN_S + 7 tfX T1_SIGMA_7 T1_LUT_SIG_S + */ + + OPJ_UINT32 lu = (fX >> (ci * 3U)) & (T1_SIGMA_1 | T1_SIGMA_3 | T1_SIGMA_5 | T1_SIGMA_7); + + lu |= (pfX >> (T1_CHI_THIS_I + (ci * 3U))) & (1U << 0); + lu |= (nfX >> (T1_CHI_THIS_I - 2U + (ci * 3U))) & (1U << 2); + if (ci == 0U) { + lu |= (fX >> (T1_CHI_0_I - 4U)) & (1U << 4); + } + else { + lu |= (fX >> (T1_CHI_1_I - 4U + ((ci - 1U) * 3U))) & (1U << 4); + } + lu |= (fX >> (T1_CHI_2_I - 6U + (ci * 3U))) & (1U << 6); + + return lut_spb_opt[lu]; +} + +static void opj_t1_updateflags_opt(opj_flag_opt_t *flagsp, OPJ_UINT32 ci, OPJ_UINT32 s, OPJ_UINT32 stride) { + /* set up to point to the north and south data points' flags words, if required */ + opj_flag_opt_t* north = NULL; + opj_flag_opt_t* south = NULL; + + /* mark target as significant */ + *flagsp |= T1_SIGMA_THIS << (3U * ci); + + /* north-west, north, north-east */ + if (ci == 0U) { + north = flagsp - stride; + *north |= T1_SIGMA_16; + north[-1] |= T1_SIGMA_17; + north[1] |= T1_SIGMA_15; + } + + /* south-west, south, south-east */ + if (ci == 3U) { + south = flagsp + stride; + *south |= T1_SIGMA_1; + south[-1] |= T1_SIGMA_2; + south[1] |= T1_SIGMA_0; + } + + /* east */ + flagsp[-1] |= T1_SIGMA_5 << (3U * ci); + + /* west */ + flagsp[1] |= T1_SIGMA_3 << (3U * ci); + + if (s) { + switch (ci) { + case 0U: + { + *flagsp |= T1_CHI_1; + *north |= T1_CHI_5; + break; + } + case 1: + *flagsp |= T1_CHI_2; + break; + case 2: + *flagsp |= T1_CHI_3; + break; + case 3: + { + *flagsp |= T1_CHI_4; + *south |= T1_CHI_0; + break; + } + + } + } +} + +static void opj_t1_enc_sigpass_step( opj_t1_opt_t *t1, + opj_flag_opt_t *flagsp, + OPJ_UINT32 *datap, + OPJ_UINT32 orient, + OPJ_INT32 bpno, + OPJ_INT32 one, + OPJ_INT32 *nmsedec) +{ + OPJ_UINT32 v; + OPJ_UINT32 ci; + + opj_mqc_t *mqc = t1->mqc; + if (*flagsp == 0U) { + return; /* Nothing to do for any of the 4 data points */ + } + for (ci = 0U; ci < 4U; ++ci) { + OPJ_UINT32 const shift_flags = *flagsp >> (ci * 3U); + /* if location is not significant, has not been coded in significance pass, and is in preferred neighbourhood, + then code in this pass: */ + if ((shift_flags & (T1_SIGMA_THIS | T1_PI_THIS)) == 0U && (shift_flags & T1_SIGMA_NEIGHBOURS) != 0U) { + v = (*datap >> one) & 1; + opj_mqc_setcurctx(mqc, opj_t1_getctxno_zc_opt(shift_flags, orient)); + opj_mqc_encode(mqc, v); + if (v) { + /* sign bit */ + v = *datap >> T1_DATA_SIGN_BIT_INDEX; + *nmsedec += opj_t1_getnmsedec_sig(*datap, (OPJ_UINT32)bpno); + opj_mqc_setcurctx(mqc, opj_t1_getctxno_sc_opt(*flagsp, flagsp[-1], flagsp[1], ci)); + opj_mqc_encode(mqc, v ^ opj_t1_getspb_opt(*flagsp, flagsp[-1], flagsp[1], ci)); + opj_t1_updateflags_opt(flagsp, ci, v, t1->flags_stride); + } + /* set propogation pass bit for this location */ + *flagsp |= T1_PI_THIS << (ci * 3U); + } + datap += t1->w; + } +} + + + +static void opj_t1_enc_sigpass(opj_t1_opt_t *t1, + OPJ_INT32 bpno, + OPJ_UINT32 orient, + OPJ_INT32 *nmsedec ) +{ + OPJ_UINT32 i, k; + OPJ_INT32 const one = (bpno + T1_NMSEDEC_FRACBITS); + OPJ_UINT32 const flag_row_extra = t1->flags_stride - t1->w; + OPJ_UINT32 const data_row_extra = (t1->w << 2) - t1->w; + + opj_flag_opt_t* f = ENC_FLAGS_ADDRESS(0, 0); + OPJ_UINT32* d = t1->data; + + *nmsedec = 0; + for (k = 0; k < t1->h; k += 4) { + for (i = 0; i < t1->w; ++i) { + opj_t1_enc_sigpass_step( + t1, + f, + d, + orient, + bpno, + one, + nmsedec); + + ++f; + ++d; + } + d += data_row_extra; + f += flag_row_extra; + } +} + +static void opj_t1_enc_refpass_step( opj_t1_opt_t *t1, + opj_flag_opt_t *flagsp, + OPJ_UINT32 *datap, + OPJ_INT32 bpno, + OPJ_INT32 one, + OPJ_INT32 *nmsedec) +{ + OPJ_UINT32 v; + OPJ_UINT32 ci; + + opj_mqc_t *mqc = t1->mqc; + + if ((*flagsp & (T1_SIGMA_4 | T1_SIGMA_7 | T1_SIGMA_10 | T1_SIGMA_13)) == 0) { + /* none significant */ + return; + } + if ((*flagsp & (T1_PI_0 | T1_PI_1 | T1_PI_2 | T1_PI_3)) == (T1_PI_0 | T1_PI_1 | T1_PI_2 | T1_PI_3)) { + /* all processed by sigpass */ + return; + } + + for (ci = 0U; ci < 4U; ++ci) { + OPJ_UINT32 shift_flags = *flagsp >> (ci * 3U); + /* if location is significant, but has not been coded in significance propagation pass, then code in this pass: */ + if ((shift_flags & (T1_SIGMA_THIS | T1_PI_THIS)) == T1_SIGMA_THIS) { + *nmsedec += opj_t1_getnmsedec_ref(*datap, (OPJ_UINT32)bpno); + v = (*datap >> one) & 1; + opj_mqc_setcurctx(mqc, opj_t1_getctxno_mag_opt(shift_flags)); + opj_mqc_encode(mqc, v); + /* flip magnitude refinement bit*/ + *flagsp |= T1_MU_THIS << (ci * 3U); + } + datap += t1->w; + } +} + +static void opj_t1_enc_refpass( + opj_t1_opt_t *t1, + OPJ_INT32 bpno, + OPJ_INT32 *nmsedec) +{ + OPJ_UINT32 i, k; + const OPJ_INT32 one = (bpno + T1_NMSEDEC_FRACBITS); + opj_flag_opt_t* f = ENC_FLAGS_ADDRESS(0, 0); + OPJ_UINT32 const flag_row_extra = t1->flags_stride - t1->w; + OPJ_UINT32 const data_row_extra = (t1->w << 2) - t1->w; + OPJ_UINT32* d = t1->data; + + *nmsedec = 0; + for (k = 0U; k < t1->h; k += 4U) { + for (i = 0U; i < t1->w; ++i) { + opj_t1_enc_refpass_step( + t1, + f, + d, + bpno, + one, + nmsedec); + ++f; + ++d; + } + f += flag_row_extra; + d += data_row_extra; + } +} + +static void opj_t1_enc_clnpass_step( + opj_t1_opt_t *t1, + opj_flag_opt_t *flagsp, + OPJ_UINT32 *datap, + OPJ_UINT32 orient, + OPJ_INT32 bpno, + OPJ_INT32 one, + OPJ_INT32 *nmsedec, + OPJ_UINT32 agg, + OPJ_UINT32 runlen, + OPJ_UINT32 y) +{ + OPJ_UINT32 v; + OPJ_UINT32 ci; + opj_mqc_t *mqc = t1->mqc; + + OPJ_UINT32 lim; + const OPJ_UINT32 check = (T1_SIGMA_4 | T1_SIGMA_7 | T1_SIGMA_10 | T1_SIGMA_13 | T1_PI_0 | T1_PI_1 | T1_PI_2 | T1_PI_3); + + if ((*flagsp & check) == check) { + if (runlen == 0) { + *flagsp &= ~(T1_PI_0 | T1_PI_1 | T1_PI_2 | T1_PI_3); + } + else if (runlen == 1) { + *flagsp &= ~(T1_PI_1 | T1_PI_2 | T1_PI_3); + } + else if (runlen == 2) { + *flagsp &= ~(T1_PI_2 | T1_PI_3); + } + else if (runlen == 3) { + *flagsp &= ~(T1_PI_3); + } + return; + } + + lim = 4U < (t1->h - y) ? 4U : (t1->h - y); + for (ci = runlen; ci < lim; ++ci) { + opj_flag_opt_t shift_flags; + if ((agg != 0) && (ci == runlen)) { + goto LABEL_PARTIAL; + } + + shift_flags = *flagsp >> (ci * 3U); + + if (!(shift_flags & (T1_SIGMA_THIS | T1_PI_THIS))) { + opj_mqc_setcurctx(mqc, opj_t1_getctxno_zc_opt(shift_flags, orient)); + v = (*datap >> one) & 1; + opj_mqc_encode(mqc, v); + if (v) { + LABEL_PARTIAL: + *nmsedec += opj_t1_getnmsedec_sig(*datap, (OPJ_UINT32)bpno); + opj_mqc_setcurctx(mqc, opj_t1_getctxno_sc_opt(*flagsp, flagsp[-1], flagsp[1], ci)); + /* sign bit */ + v = *datap >> T1_DATA_SIGN_BIT_INDEX; + opj_mqc_encode(mqc, v ^ opj_t1_getspb_opt(*flagsp, flagsp[-1], flagsp[1], ci)); + opj_t1_updateflags_opt(flagsp, ci, v, t1->flags_stride); + } + } + *flagsp &= ~(T1_PI_0 << (3U * ci)); + datap += t1->w; + } +} + + +static void opj_t1_enc_clnpass( + opj_t1_opt_t *t1, + OPJ_INT32 bpno, + OPJ_UINT32 orient, + OPJ_INT32 *nmsedec) +{ + OPJ_UINT32 i, k; + const OPJ_INT32 one = (bpno + T1_NMSEDEC_FRACBITS); + OPJ_UINT32 agg, runlen; + + opj_mqc_t *mqc = t1->mqc; + + *nmsedec = 0; + + for (k = 0; k < t1->h; k += 4) { + for (i = 0; i < t1->w; ++i) { + agg = !ENC_FLAGS(i, k); + if (agg) { + for (runlen = 0; runlen < 4; ++runlen) { + if ( (t1->data[((k + runlen)*t1->w) + i] >> one) & 1) + break; + } + opj_mqc_setcurctx(mqc, T1_CTXNO_AGG); + opj_mqc_encode(mqc, runlen != 4); + if (runlen == 4) { + continue; + } + opj_mqc_setcurctx(mqc, T1_CTXNO_UNI); + opj_mqc_encode(mqc, runlen >> 1); + opj_mqc_encode(mqc, runlen & 1); + } + else { + runlen = 0; + } + opj_t1_enc_clnpass_step( + t1, + ENC_FLAGS_ADDRESS(i, k), + t1->data + ((k + runlen) * t1->w) + i, + orient, + bpno, + one, + nmsedec, + agg, + runlen, + k); + } + } +} + + +static OPJ_BOOL opj_t1_allocate_buffers( + opj_t1_opt_t *t1, + OPJ_UINT32 w, + OPJ_UINT32 h) +{ + OPJ_UINT32 datasize = w * h; + OPJ_UINT32 flagssize; + OPJ_UINT32 x; + opj_flag_opt_t* p; + OPJ_UINT32 flags_height; + + if (datasize > t1->datasize) { + opj_aligned_free(t1->data); + t1->data = (OPJ_UINT32*)opj_aligned_malloc(datasize * sizeof(OPJ_INT32)); + if (!t1->data) { + /* FIXME event manager error callback */ + return OPJ_FALSE; + } + t1->datasize = datasize; + } + memset(t1->data, 0, datasize * sizeof(OPJ_INT32)); + + + t1->flags_stride = w + 2; + flags_height = (h + 3U) / 4U; + flagssize = t1->flags_stride * (flags_height + 2); + if (flagssize > t1->flagssize) { + opj_aligned_free(t1->flags); + t1->flags = (opj_flag_opt_t*)opj_aligned_malloc(flagssize * sizeof(opj_flag_opt_t)); + if (!t1->flags) { + /* FIXME event manager error callback */ + return OPJ_FALSE; + } + t1->flagssize = flagssize; + } + memset(t1->flags, 0, flagssize * sizeof(opj_flag_opt_t)); /* Shall we keep memset for encoder ? */ + + + /* BIG FAT XXX */ + p = &t1->flags[0]; + for (x = 0; x < t1->flags_stride; ++x) { + /* magic value to hopefully stop any passes being interested in this entry */ + *p++ = (T1_PI_0 | T1_PI_1 | T1_PI_2 | T1_PI_3); + } + + p = &t1->flags[((flags_height + 1) * t1->flags_stride)]; + for (x = 0; x < t1->flags_stride; ++x) { + /* magic value to hopefully stop any passes being interested in this entry */ + *p++ = (T1_PI_0 | T1_PI_1 | T1_PI_2 | T1_PI_3); + } + + if (h % 4) { + OPJ_UINT32 v = 0; + p = &t1->flags[((flags_height)* t1->flags_stride)]; + if (h % 4 == 1) { + v |= T1_PI_1 | T1_PI_2 | T1_PI_3; + } + else if (h % 4 == 2) { + v |= T1_PI_2 | T1_PI_3; + } + else if (h % 4 == 3) { + v |= T1_PI_3; + } + for (x = 0; x < t1->flags_stride; ++x) { + *p++ = v; + } + } + + + t1->w = w; + t1->h = h; + + return OPJ_TRUE; +} + +/* ----------------------------------------------------------------------- */ + +/* ----------------------------------------------------------------------- */ + +OPJ_BOOL opj_t1_opt_encode_cblks( opj_tcd_tile_t *tile, + opj_tcp_t *tcp, + const OPJ_FLOAT64 * mct_norms, + OPJ_UINT32 mct_numcomps ) +{ + OPJ_UINT32 compno, resno, bandno, precno; + OPJ_BOOL rc = OPJ_TRUE; + tile->distotile = 0; /* fixed_quality */ + for (compno = 0; compno < tile->numcomps; ++compno) { + opj_tcd_tilecomp_t* tilec = &tile->comps[compno]; + opj_tccp_t* tccp = &tcp->tccps[compno]; + OPJ_UINT32 tile_w = (OPJ_UINT32)(tilec->x1 - tilec->x0); + + for (resno = 0; resno < tilec->numresolutions; ++resno) { + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + + for (bandno = 0; bandno < res->numbands; ++bandno) { + opj_tcd_band_t* restrict band = &res->bands[bandno]; + OPJ_INT32 bandconst = 8192 * 8192 / ((OPJ_INT32) floor(band->stepsize * 8192)); + + for (precno = 0; precno < res->pw * res->ph; ++precno) { + opj_tcd_precinct_t *prc = &band->precincts[precno]; + OPJ_INT32 cblkno; + OPJ_INT32 bandOdd = band->bandno & 1; + OPJ_INT32 bandModTwo = band->bandno & 2; + +#ifdef _OPENMP +#pragma omp parallel default(none) private(cblkno) shared(band, bandOdd, bandModTwo, prc, tilec, tccp, mct_norms, mct_numcomps, bandconst,compno, tile, tile_w, resno, rc) + { + + #pragma omp for +#endif + for (cblkno = 0; cblkno < (OPJ_INT32)(prc->cw * prc->ch); ++cblkno) { + OPJ_INT32* restrict tiledp; + opj_tcd_cblk_enc_t* cblk = prc->cblks.enc + cblkno; + OPJ_UINT32 cblk_w; + OPJ_UINT32 cblk_h; + OPJ_UINT32 i, j, tileIndex=0, tileLineAdvance; + OPJ_UINT32 cblk_index = 0; + opj_t1_opt_t * t1 = 00; + OPJ_INT32 x = cblk->x0 - band->x0; + OPJ_INT32 y = cblk->y0 - band->y0; + OPJ_UINT32 max=0; + + if (bandOdd) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + x += pres->x1 - pres->x0; + } + if (bandModTwo) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + y += pres->y1 - pres->y0; + } + t1 = opj_t1_create(OPJ_TRUE); + if (!t1) { + rc = OPJ_FALSE; + continue; + } + if(!opj_t1_allocate_buffers( + t1, + (OPJ_UINT32)(cblk->x1 - cblk->x0), + (OPJ_UINT32)(cblk->y1 - cblk->y0))) + { + opj_t1_destroy(t1); + rc = OPJ_FALSE; + continue; + } + cblk_w = t1->w; + cblk_h = t1->h; + tileLineAdvance = tile_w - cblk_w; + + tiledp=&tilec->data[(OPJ_UINT32)y * tile_w + (OPJ_UINT32)x]; + if (tccp->qmfbid == 1) { + for (j = 0; j < cblk_h; ++j) { + for (i = 0; i < cblk_w; ++i) { + OPJ_INT32 tmp = tiledp[tileIndex] << T1_NMSEDEC_FRACBITS; + OPJ_UINT32 mag = (OPJ_UINT32)opj_int_abs(tmp); + max = opj_uint_max(max, mag); + t1->data[cblk_index] = mag | ((OPJ_UINT32)(tmp < 0) << T1_DATA_SIGN_BIT_INDEX); + tileIndex++; + cblk_index++; + } + tileIndex += tileLineAdvance; + } + } else { /* if (tccp->qmfbid == 0) */ + for (j = 0; j < cblk_h; ++j) { + for (i = 0; i < cblk_w; ++i) { + OPJ_INT32 tmp = opj_int_fix_mul_t1(tiledp[tileIndex], bandconst); + OPJ_UINT32 mag = (OPJ_UINT32)opj_int_abs(tmp); + OPJ_UINT32 sign_mag = mag | ((OPJ_UINT32)(tmp < 0) << T1_DATA_SIGN_BIT_INDEX); + max = opj_uint_max(max, mag); + t1->data[cblk_index] = sign_mag; + tileIndex++; + cblk_index++; + } + tileIndex += tileLineAdvance; + } + } + + opj_t1_encode_cblk( + t1, + cblk, + band->bandno, + compno, + tilec->numresolutions - 1 - resno, + tccp->qmfbid, + band->stepsize, + tile->numcomps, + tile, + mct_norms, + mct_numcomps, + max); + opj_t1_destroy(t1); + + } /* cblkno */ +#ifdef _OPENMP + } +#endif + } /* precno */ + } /* bandno */ + } /* resno */ + } /* compno */ + return rc; +} + +/** mod fixed_quality */ +static void opj_t1_encode_cblk(opj_t1_opt_t *t1, + opj_tcd_cblk_enc_t* cblk, + OPJ_UINT32 orient, + OPJ_UINT32 compno, + OPJ_UINT32 level, + OPJ_UINT32 qmfbid, + OPJ_FLOAT64 stepsize, + OPJ_UINT32 numcomps, + opj_tcd_tile_t * tile, + const OPJ_FLOAT64 * mct_norms, + OPJ_UINT32 mct_numcomps, + OPJ_UINT32 max) +{ + OPJ_FLOAT64 cumwmsedec = 0.0; + + opj_mqc_t *mqc = t1->mqc; + + OPJ_UINT32 passno; + OPJ_INT32 bpno; + OPJ_UINT32 passtype; + OPJ_INT32 nmsedec = 0; + OPJ_FLOAT64 tempwmsedec; + + cblk->numbps = max ? (OPJ_UINT32)((opj_int_floorlog2((OPJ_INT32)max) + 1) - T1_NMSEDEC_FRACBITS) : 0; + + bpno = (OPJ_INT32)(cblk->numbps - 1); + passtype = 2; + + opj_mqc_resetstates(mqc); + opj_mqc_setstate(mqc, T1_CTXNO_UNI, 0, 46); + opj_mqc_setstate(mqc, T1_CTXNO_AGG, 0, 3); + opj_mqc_setstate(mqc, T1_CTXNO_ZC, 0, 4); + opj_mqc_init_enc(mqc, cblk->data); + + for (passno = 0; bpno >= 0; ++passno) { + opj_tcd_pass_t *pass = &cblk->passes[passno]; + OPJ_UINT32 correction = 3; + switch (passtype) { + case 0: + opj_t1_enc_sigpass(t1, bpno, orient, &nmsedec); + break; + case 1: + opj_t1_enc_refpass(t1, bpno, &nmsedec); + break; + case 2: + opj_t1_enc_clnpass(t1, bpno, orient, &nmsedec); + break; + } + + /* fixed_quality */ + tempwmsedec = opj_t1_getwmsedec(nmsedec, compno, level, orient, bpno, qmfbid, stepsize, numcomps,mct_norms, mct_numcomps) ; + cumwmsedec += tempwmsedec; + tile->distotile += tempwmsedec; + pass->term = 0; + if (++passtype == 3) { + passtype = 0; + bpno--; + } + pass->distortiondec = cumwmsedec; + pass->rate = opj_mqc_numbytes(mqc) + correction; + } + + opj_mqc_flush(mqc); + cblk->totalpasses = passno; + + for (passno = 0; passnototalpasses; passno++) { + opj_tcd_pass_t *pass = &cblk->passes[passno]; + if (pass->rate > opj_mqc_numbytes(mqc)) + pass->rate = opj_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); + } +} \ No newline at end of file diff --git a/src/lib/openjp2/t1_opt.h b/src/lib/openjp2/t1_opt.h new file mode 100644 index 000000000..6fae823ba --- /dev/null +++ b/src/lib/openjp2/t1_opt.h @@ -0,0 +1,179 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux + * Copyright (c) 2003-2014, Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#pragma once + +/*********************/ +/* STATE FLAGS */ +/*********************/ + + + /** We hold the state of individual data points for the T1 encoder using + * a single 32-bit flags word to hold the state of 4 data points. This corresponds + * to the 4-point-high columns that the data is processed in. + * + * These #defines declare the layout of a 32-bit flags word. + * + * This is currently done for encoding only. + */ + +/* T1_SIGMA_XXX is significance flag for stripe column and neighbouring locations: 18 locations in total */ + +#define T1_SIGMA_0 (1U << 0) +#define T1_SIGMA_1 (1U << 1) +#define T1_SIGMA_2 (1U << 2) +#define T1_SIGMA_3 (1U << 3) +#define T1_SIGMA_4 (1U << 4) +#define T1_SIGMA_5 (1U << 5) +#define T1_SIGMA_6 (1U << 6) +#define T1_SIGMA_7 (1U << 7) +#define T1_SIGMA_8 (1U << 8) +#define T1_SIGMA_9 (1U << 9) +#define T1_SIGMA_10 (1U << 10) +#define T1_SIGMA_11 (1U << 11) +#define T1_SIGMA_12 (1U << 12) +#define T1_SIGMA_13 (1U << 13) +#define T1_SIGMA_14 (1U << 14) +#define T1_SIGMA_15 (1U << 15) +#define T1_SIGMA_16 (1U << 16) +#define T1_SIGMA_17 (1U << 17) + + +/* +* +* T1_CHI_X is the sign flag for the (X+1)th location in the stripe column. +* T1_PI_X indicates whether Xth location was coded in significance propagation pass +* T1_MU_X indicates whether Xth location belongs to the magnitude refinement pass + +*/ + +#define T1_CHI_0 (1U << 18) +#define T1_CHI_0_I 18 +#define T1_CHI_1 (1U << 19) +#define T1_CHI_1_I 19 +#define T1_MU_0 (1U << 20) +#define T1_PI_0 (1U << 21) +#define T1_CHI_2 (1U << 22) +#define T1_CHI_2_I 22 +#define T1_MU_1 (1U << 23) +#define T1_PI_1 (1U << 24) +#define T1_CHI_3 (1U << 25) +#define T1_MU_2 (1U << 26) +#define T1_PI_2 (1U << 27) +#define T1_CHI_4 (1U << 28) +#define T1_MU_3 (1U << 29) +#define T1_PI_3 (1U << 30) +#define T1_CHI_5 (1U << 31) + + + +/** As an example, the bits T1_SIGMA_3, T1_SIGMA_4 and T1_SIGMA_5 +* indicate the significance state of the west neighbour of data point zero +* of our four, the point itself, and its east neighbour respectively. +* Many of the bits are arranged so that given a flags word, you can +* look at the values for the data point 0, then shift the flags +* word right by 3 bits and look at the same bit positions to see the +* values for data point 1. +* +* The #defines below are convenience flags; say you have a flags word +* f, you can do things like +* +* (f & T1_SIGMA_THIS) +* +* to see the significance bit of data point 0, then do +* +* ((f >> 3) & T1_SIGMA_THIS) +* +* to see the significance bit of data point 1. +*/ + +#define T1_SIGMA_NW T1_SIGMA_0 +#define T1_SIGMA_N T1_SIGMA_1 +#define T1_SIGMA_NE T1_SIGMA_2 +#define T1_SIGMA_W T1_SIGMA_3 +#define T1_SIGMA_THIS T1_SIGMA_4 +#define T1_SIGMA_E T1_SIGMA_5 +#define T1_SIGMA_SW T1_SIGMA_6 +#define T1_SIGMA_S T1_SIGMA_7 +#define T1_SIGMA_SE T1_SIGMA_8 +#define T1_SIGMA_NEIGHBOURS (T1_SIGMA_NW | T1_SIGMA_N | T1_SIGMA_NE | T1_SIGMA_W | T1_SIGMA_E | T1_SIGMA_SW | T1_SIGMA_S | T1_SIGMA_SE) + + + +#define T1_CHI_THIS T1_CHI_1 +#define T1_CHI_THIS_I T1_CHI_1_I +#define T1_MU_THIS T1_MU_0 +#define T1_PI_THIS T1_PI_0 + +#define T1_LUT_SGN_W (1U << 0) +#define T1_LUT_SIG_N (1U << 1) +#define T1_LUT_SGN_E (1U << 2) +#define T1_LUT_SIG_W (1U << 3) +#define T1_LUT_SGN_N (1U << 4) +#define T1_LUT_SIG_E (1U << 5) +#define T1_LUT_SGN_S (1U << 6) +#define T1_LUT_SIG_S (1U << 7) + +#define T1_DATA_SIGN_BIT_INDEX 31 +#define T1_DATA_SIGN_BIT (1U << T1_DATA_SIGN_BIT_INDEX) + + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ + +/** +Encode the code-blocks of a tile using optimized algorithm +@param t1 T1 handle +@param tile The tile to encode +@param tcp Tile coding parameters +@param mct_norms FIXME DOC +@param mct_numcomps Number of components used for MCT +*/ +OPJ_BOOL opj_t1_opt_encode_cblks( opj_tcd_tile_t *tile, + opj_tcp_t *tcp, + const OPJ_FLOAT64 * mct_norms, + OPJ_UINT32 mct_numcomps); + + + + +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + + diff --git a/src/lib/openjp2/t2.c b/src/lib/openjp2/t2.c index ebc26b2dd..3d2946f3c 100644 --- a/src/lib/openjp2/t2.c +++ b/src/lib/openjp2/t2.c @@ -77,6 +77,26 @@ static OPJ_BOOL opj_t2_encode_packet( OPJ_UINT32 tileno, OPJ_UINT32 len, opj_codestream_info_t *cstr_info); +/** +Encode a packet of a tile to a destination buffer +@param tileno Number of the tile encoded +@param tile Tile for which to write the packets +@param tcp Tile coding parameters +@param pi Packet identity +@param dest Destination buffer +@param p_data_written FIXME DOC +@param len Length of the destination buffer +@param cstr_info Codestream information structure +@return +*/ +static OPJ_BOOL opj_t2_encode_packet_thresh(opj_tcd_tile_t *tile, + opj_tcp_t *tcp, + opj_pi_iterator_t *pi, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 len); + + + /** Decode a packet of a tile from a source buffer @param t2 T2 handle @@ -94,9 +114,8 @@ static OPJ_BOOL opj_t2_decode_packet( opj_t2_t* t2, opj_tcd_tile_t *tile, opj_tcp_t *tcp, opj_pi_iterator_t *pi, - OPJ_BYTE *src, + opj_seg_buf_t* src_buf, OPJ_UINT32 * data_read, - OPJ_UINT32 max_length, opj_packet_info_t *pack_info, opj_event_mgr_t *p_manager); @@ -104,9 +123,8 @@ static OPJ_BOOL opj_t2_skip_packet( opj_t2_t* p_t2, opj_tcd_tile_t *p_tile, opj_tcp_t *p_tcp, opj_pi_iterator_t *p_pi, - OPJ_BYTE *p_src, + opj_seg_buf_t* src_buf, OPJ_UINT32 * p_data_read, - OPJ_UINT32 p_max_length, opj_packet_info_t *p_pack_info, opj_event_mgr_t *p_manager); @@ -115,18 +133,16 @@ static OPJ_BOOL opj_t2_read_packet_header( opj_t2_t* p_t2, opj_tcp_t *p_tcp, opj_pi_iterator_t *p_pi, OPJ_BOOL * p_is_data_present, - OPJ_BYTE *p_src_data, + opj_seg_buf_t* src_buf, OPJ_UINT32 * p_data_read, - OPJ_UINT32 p_max_length, opj_packet_info_t *p_pack_info, opj_event_mgr_t *p_manager); static OPJ_BOOL opj_t2_read_packet_data(opj_t2_t* p_t2, opj_tcd_tile_t *p_tile, opj_pi_iterator_t *p_pi, - OPJ_BYTE *p_src_data, + opj_seg_buf_t* src_buf, OPJ_UINT32 * p_data_read, - OPJ_UINT32 p_max_length, opj_packet_info_t *pack_info, opj_event_mgr_t *p_manager); @@ -211,126 +227,146 @@ OPJ_BOOL opj_t2_encode_packets( opj_t2_t* p_t2, 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_UINT32 p_pino) { OPJ_BYTE *l_current_data = p_dest; OPJ_UINT32 l_nb_bytes = 0; - OPJ_UINT32 compno; - OPJ_UINT32 poc; opj_pi_iterator_t *l_pi = 00; opj_pi_iterator_t *l_current_pi = 00; opj_image_t *l_image = p_t2->image; opj_cp_t *l_cp = p_t2->cp; opj_tcp_t *l_tcp = &l_cp->tcps[p_tile_no]; - OPJ_UINT32 pocno = (l_cp->rsiz == OPJ_PROFILE_CINEMA_4K)? 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 = opj_pi_initialise_encode(l_image, l_cp, p_tile_no, p_t2_mode); + l_pi = opj_pi_initialise_encode(l_image, l_cp, p_tile_no, FINAL_PASS); 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; + opj_pi_create_encode(l_pi, l_cp,p_tile_no,p_pino,p_tp_num,p_tp_pos, FINAL_PASS); - /* TODO MSD : check why this function cannot fail (cf. v1) */ - opj_pi_create_encode(l_pi, l_cp,p_tile_no,poc,l_tp_num,p_tp_pos,p_t2_mode); + l_current_pi = &l_pi[p_pino]; + if (l_current_pi->poc.prg == OPJ_PROG_UNKNOWN) { + /* TODO ADE : add an error */ + opj_pi_destroy(l_pi, l_nb_pocs); + return OPJ_FALSE; + } + while (opj_pi_next(l_current_pi)) { + if (l_current_pi->layno < p_maxlayers) { + l_nb_bytes=0; - if (l_current_pi->poc.prg == OPJ_PROG_UNKNOWN) { - /* TODO ADE : add an error */ + if (! opj_t2_encode_packet(p_tile_no,p_tile, l_tcp, l_current_pi, l_current_data, &l_nb_bytes, p_max_len, cstr_info)) { opj_pi_destroy(l_pi, l_nb_pocs); return OPJ_FALSE; - } - while (opj_pi_next(l_current_pi)) { - if (l_current_pi->layno < p_maxlayers) { - l_nb_bytes = 0; - - if (! opj_t2_encode_packet(p_tile_no,p_tile, l_tcp, l_current_pi, l_current_data, &l_nb_bytes, p_max_len, cstr_info)) { - opj_pi_destroy(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) { - opj_pi_destroy(l_pi, l_nb_pocs); - return OPJ_FALSE; - } - } - - ++l_current_pi; - } - } - } - else { /* t2_mode == FINAL_PASS */ - opj_pi_create_encode(l_pi, l_cp,p_tile_no,p_pino,p_tp_num,p_tp_pos,p_t2_mode); - - l_current_pi = &l_pi[p_pino]; - if (l_current_pi->poc.prg == OPJ_PROG_UNKNOWN) { - /* TODO ADE : add an error */ - opj_pi_destroy(l_pi, l_nb_pocs); - return OPJ_FALSE; - } - while (opj_pi_next(l_current_pi)) { - if (l_current_pi->layno < p_maxlayers) { - l_nb_bytes=0; - - if (! opj_t2_encode_packet(p_tile_no,p_tile, l_tcp, l_current_pi, l_current_data, &l_nb_bytes, p_max_len, cstr_info)) { - opj_pi_destroy(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; - } - } - } + } + + 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; + } + } + opj_pi_destroy(l_pi, l_nb_pocs); return OPJ_TRUE; } + +OPJ_BOOL opj_t2_encode_packets_thresh(opj_t2_t* p_t2, + OPJ_UINT32 p_tile_no, + opj_tcd_tile_t *p_tile, + OPJ_UINT32 p_maxlayers, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 p_max_len, + OPJ_INT32 p_tp_pos) +{ + OPJ_UINT32 l_nb_bytes = 0; + OPJ_UINT32 compno; + OPJ_UINT32 poc; + opj_pi_iterator_t *l_pi = 00; + opj_pi_iterator_t *l_current_pi = 00; + opj_image_t *l_image = p_t2->image; + opj_cp_t *l_cp = p_t2->cp; + opj_tcp_t *l_tcp = l_cp->tcps + p_tile_no; + OPJ_UINT32 pocno = (l_cp->rsiz == OPJ_PROFILE_CINEMA_4K) ? 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 = opj_pi_initialise_encode(l_image, l_cp, p_tile_no, THRESH_CALC); + if (!l_pi) { + return OPJ_FALSE; + } + *p_data_written = 0; + 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; + + /* TODO MSD : check why this function cannot fail (cf. v1) */ + opj_pi_create_encode(l_pi, l_cp, p_tile_no, poc, l_tp_num, p_tp_pos, THRESH_CALC); + + if (l_current_pi->poc.prg == OPJ_PROG_UNKNOWN) { + /* TODO ADE : add an error */ + opj_pi_destroy(l_pi, l_nb_pocs); + return OPJ_FALSE; + } + while (opj_pi_next(l_current_pi)) { + if (l_current_pi->layno < p_maxlayers) { + l_nb_bytes = 0; + + if (!opj_t2_encode_packet_thresh(p_tile, l_tcp, l_current_pi, &l_nb_bytes, p_max_len)) { + opj_pi_destroy(l_pi, l_nb_pocs); + return OPJ_FALSE; + } + + l_comp_len += 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) { + opj_pi_destroy(l_pi, l_nb_pocs); + return OPJ_FALSE; + } + } + + ++l_current_pi; + } + } + opj_pi_destroy(l_pi, l_nb_pocs); + return OPJ_TRUE; +} + /* see issue 80 */ #if 0 #define JAS_FPRINTF fprintf @@ -347,13 +383,11 @@ static void opj_null_jas_fprintf(FILE* file, const char * format, ...) OPJ_BOOL opj_t2_decode_packets( opj_t2_t *p_t2, OPJ_UINT32 p_tile_no, opj_tcd_tile_t *p_tile, - OPJ_BYTE *p_src, + opj_seg_buf_t* src_buf, OPJ_UINT32 * p_data_read, - OPJ_UINT32 p_max_len, opj_codestream_index_t *p_cstr_index, opj_event_mgr_t *p_manager) { - OPJ_BYTE *l_current_data = p_src; opj_pi_iterator_t *l_pi = 00; OPJ_UINT32 pino; opj_image_t *l_image = p_t2->image; @@ -419,7 +453,9 @@ OPJ_BOOL opj_t2_decode_packets( opj_t2_t *p_t2, first_pass_failed[l_current_pi->compno] = OPJ_FALSE; - if (! opj_t2_decode_packet(p_t2,p_tile,l_tcp,l_current_pi,l_current_data,&l_nb_bytes_read,p_max_len,l_pack_info, p_manager)) { + if (! opj_t2_decode_packet(p_t2,p_tile,l_tcp,l_current_pi, + src_buf,&l_nb_bytes_read, + l_pack_info, p_manager)) { opj_pi_destroy(l_pi,l_nb_pocs); opj_free(first_pass_failed); return OPJ_FALSE; @@ -430,7 +466,10 @@ OPJ_BOOL opj_t2_decode_packets( opj_t2_t *p_t2, } else { l_nb_bytes_read = 0; - if (! opj_t2_skip_packet(p_t2,p_tile,l_tcp,l_current_pi,l_current_data,&l_nb_bytes_read,p_max_len,l_pack_info, p_manager)) { + if (! opj_t2_skip_packet(p_t2,p_tile,l_tcp,l_current_pi, + src_buf, + &l_nb_bytes_read, + l_pack_info, p_manager)) { opj_pi_destroy(l_pi,l_nb_pocs); opj_free(first_pass_failed); return OPJ_FALSE; @@ -443,8 +482,8 @@ OPJ_BOOL opj_t2_decode_packets( opj_t2_t *p_t2, l_img_comp->resno_decoded = p_tile->comps[l_current_pi->compno].minimum_num_resolutions - 1; } - l_current_data += l_nb_bytes_read; - p_max_len -= l_nb_bytes_read; + *p_data_read += l_nb_bytes_read; + /* INDEX >> */ #ifdef TODO_MSD @@ -484,7 +523,6 @@ OPJ_BOOL opj_t2_decode_packets( opj_t2_t *p_t2, /* don't forget to release pi */ opj_pi_destroy(l_pi,l_nb_pocs); - *p_data_read = (OPJ_UINT32)(l_current_data - p_src); return OPJ_TRUE; } @@ -521,9 +559,8 @@ static OPJ_BOOL opj_t2_decode_packet( opj_t2_t* p_t2, opj_tcd_tile_t *p_tile, opj_tcp_t *p_tcp, opj_pi_iterator_t *p_pi, - OPJ_BYTE *p_src, + opj_seg_buf_t* src_buf, OPJ_UINT32 * p_data_read, - OPJ_UINT32 p_max_length, opj_packet_info_t *p_pack_info, opj_event_mgr_t *p_manager) { @@ -533,22 +570,24 @@ static OPJ_BOOL opj_t2_decode_packet( opj_t2_t* p_t2, *p_data_read = 0; - if (! opj_t2_read_packet_header(p_t2,p_tile,p_tcp,p_pi,&l_read_data,p_src,&l_nb_bytes_read,p_max_length,p_pack_info, p_manager)) { + if (! opj_t2_read_packet_header(p_t2,p_tile,p_tcp,p_pi,&l_read_data, + src_buf, + &l_nb_bytes_read, + p_pack_info, p_manager)) { return OPJ_FALSE; } - p_src += l_nb_bytes_read; l_nb_total_bytes_read += l_nb_bytes_read; - p_max_length -= l_nb_bytes_read; /* we should read data for the packet */ if (l_read_data) { l_nb_bytes_read = 0; - if (! opj_t2_read_packet_data(p_t2,p_tile,p_pi,p_src,&l_nb_bytes_read,p_max_length,p_pack_info, p_manager)) { + if (! opj_t2_read_packet_data(p_t2,p_tile,p_pi, + src_buf,&l_nb_bytes_read, + p_pack_info, p_manager)) { return OPJ_FALSE; } - l_nb_total_bytes_read += l_nb_bytes_read; } @@ -793,41 +832,246 @@ static OPJ_BOOL opj_t2_encode_packet( OPJ_UINT32 tileno, return OPJ_TRUE; } + +static OPJ_BOOL opj_t2_encode_packet_thresh(opj_tcd_tile_t * tile, + opj_tcp_t * tcp, + opj_pi_iterator_t *pi, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 length) +{ + OPJ_UINT32 bandno, cblkno; + OPJ_UINT32 l_nb_bytes; + OPJ_UINT32 compno = pi->compno; /* component value */ + OPJ_UINT32 resno = pi->resno; /* resolution level value */ + OPJ_UINT32 precno = pi->precno; /* precinct value */ + OPJ_UINT32 layno = pi->layno; /* quality layer value */ + OPJ_UINT32 l_nb_blocks; + opj_tcd_band_t *band = 00; + opj_tcd_cblk_enc_t* cblk = 00; + opj_tcd_pass_t *pass = 00; + + opj_tcd_tilecomp_t *tilec = tile->comps + compno; + opj_tcd_resolution_t *res = tilec->resolutions + resno; + + opj_bio_t *bio = 00; /* BIO component */ + OPJ_UINT32 packet_bytes_written = 0; + + /* */ + if (tcp->csty & J2K_CP_CSTY_SOP) { + length -= 6; + packet_bytes_written += 6; + } + /* */ + + if (!layno) { + band = res->bands; + + for (bandno = 0; bandno < res->numbands; ++bandno) { + opj_tcd_precinct_t *prc = band->precincts + precno; + + opj_tgt_reset(prc->incltree); + opj_tgt_reset(prc->imsbtree); + + l_nb_blocks = prc->cw * prc->ch; + for (cblkno = 0; cblkno < l_nb_blocks; ++cblkno) { + cblk = prc->cblks.enc+cblkno; + + cblk->numpasses = 0; + opj_tgt_setvalue(prc->imsbtree, cblkno, band->numbps - (OPJ_INT32)cblk->numbps); + } + ++band; + } + } + + bio = opj_bio_create(); + if (!bio) { + /* FIXME event manager error callback */ + return OPJ_FALSE; + } + opj_bio_init_enc(bio, 0, length); + opj_bio_write(bio, 1, 1); /* Empty header bit */ + bio->simOut = OPJ_TRUE; + + /* Writing Packet header */ + band = res->bands; + for (bandno = 0; bandno < res->numbands; ++bandno) { + opj_tcd_precinct_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) { + opj_tgt_setvalue(prc->incltree, cblkno, (OPJ_INT32)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) { + opj_tgt_encode(bio, prc->incltree, cblkno, (OPJ_INT32)(layno + 1)); + } + else { + opj_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; + opj_tgt_encode(bio, prc->imsbtree, cblkno, 999); + } + + /* number of coding passes included */ + opj_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 = (OPJ_UINT32)opj_int_max((OPJ_INT32)increment, opj_int_floorlog2((OPJ_INT32)len) + 1 + - ((OPJ_INT32)cblk->numlenbits + opj_int_floorlog2((OPJ_INT32)nump))); + len = 0; + nump = 0; + } + + ++pass; + } + opj_t2_putcommacode(bio, (OPJ_INT32)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) { + opj_bio_write(bio, (OPJ_UINT32)len, cblk->numlenbits + (OPJ_UINT32)opj_int_floorlog2((OPJ_INT32)nump)); + len = 0; + nump = 0; + } + ++pass; + } + + ++cblk; + } + + ++band; + } + + if (!opj_bio_flush(bio)) { + opj_bio_destroy(bio); + return OPJ_FALSE; + } + + l_nb_bytes = (OPJ_UINT32)opj_bio_numbytes(bio); + packet_bytes_written += l_nb_bytes; + length -= l_nb_bytes; + + opj_bio_destroy(bio); + + /* */ + if (tcp->csty & J2K_CP_CSTY_EPH) { + length -= 2; + packet_bytes_written += 2; + } + /* */ + + + /* Writing the packet body */ + band = res->bands; + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_precinct_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; + } + + cblk->numpasses += layer->numpasses; + packet_bytes_written += layer->len; + length -= layer->len; + ++cblk; + } + ++band; + } + *p_data_written += packet_bytes_written; + + return OPJ_TRUE; +} static OPJ_BOOL opj_t2_skip_packet( opj_t2_t* p_t2, opj_tcd_tile_t *p_tile, opj_tcp_t *p_tcp, opj_pi_iterator_t *p_pi, - OPJ_BYTE *p_src, + opj_seg_buf_t* src_buf, OPJ_UINT32 * p_data_read, - OPJ_UINT32 p_max_length, opj_packet_info_t *p_pack_info, opj_event_mgr_t *p_manager) { OPJ_BOOL l_read_data; OPJ_UINT32 l_nb_bytes_read = 0; OPJ_UINT32 l_nb_total_bytes_read = 0; + OPJ_UINT32 p_max_length = (OPJ_UINT32)opj_seg_buf_get_cur_seg_len(src_buf); *p_data_read = 0; - if (! opj_t2_read_packet_header(p_t2,p_tile,p_tcp,p_pi,&l_read_data,p_src,&l_nb_bytes_read,p_max_length,p_pack_info, p_manager)) { + if (! opj_t2_read_packet_header(p_t2,p_tile,p_tcp,p_pi,&l_read_data, + src_buf, + &l_nb_bytes_read, + p_pack_info, p_manager)) { return OPJ_FALSE; } - p_src += l_nb_bytes_read; l_nb_total_bytes_read += l_nb_bytes_read; - p_max_length -= l_nb_bytes_read; + p_max_length -= l_nb_bytes_read; /* we should read data for the packet */ if (l_read_data) { l_nb_bytes_read = 0; - if (! opj_t2_skip_packet_data(p_t2,p_tile,p_pi,&l_nb_bytes_read,p_max_length,p_pack_info, p_manager)) { + if (! opj_t2_skip_packet_data(p_t2,p_tile,p_pi, + &l_nb_bytes_read, + p_max_length,p_pack_info, p_manager)) { return OPJ_FALSE; } - + opj_seg_buf_incr_cur_seg_offset(src_buf, l_nb_bytes_read); l_nb_total_bytes_read += l_nb_bytes_read; } *p_data_read = l_nb_total_bytes_read; + return OPJ_TRUE; } @@ -838,13 +1082,14 @@ static OPJ_BOOL opj_t2_read_packet_header( opj_t2_t* p_t2, opj_tcp_t *p_tcp, opj_pi_iterator_t *p_pi, OPJ_BOOL * p_is_data_present, - OPJ_BYTE *p_src_data, + opj_seg_buf_t* src_buf, OPJ_UINT32 * p_data_read, - OPJ_UINT32 p_max_length, opj_packet_info_t *p_pack_info, opj_event_mgr_t *p_manager) { + OPJ_BYTE *p_src_data = opj_seg_buf_get_global_ptr(src_buf); + OPJ_UINT32 p_max_length = (OPJ_UINT32)opj_seg_buf_get_cur_seg_len(src_buf); /* loop */ OPJ_UINT32 bandno, cblkno; OPJ_UINT32 l_nb_code_blocks; @@ -966,6 +1211,7 @@ static OPJ_BOOL opj_t2_read_packet_header( opj_t2_t* p_t2, * p_is_data_present = OPJ_FALSE; *p_data_read = (OPJ_UINT32)(l_current_data - p_src_data); + opj_seg_buf_incr_cur_seg_offset(src_buf, *p_data_read); return OPJ_TRUE; } @@ -1096,6 +1342,7 @@ static OPJ_BOOL opj_t2_read_packet_header( opj_t2_t* p_t2, *p_is_data_present = OPJ_TRUE; *p_data_read = (OPJ_UINT32)(l_current_data - p_src_data); + opj_seg_buf_incr_cur_seg_offset(src_buf, *p_data_read); return OPJ_TRUE; } @@ -1103,15 +1350,13 @@ static OPJ_BOOL opj_t2_read_packet_header( opj_t2_t* p_t2, static OPJ_BOOL opj_t2_read_packet_data( opj_t2_t* p_t2, opj_tcd_tile_t *p_tile, opj_pi_iterator_t *p_pi, - OPJ_BYTE *p_src_data, + opj_seg_buf_t* src_buf, OPJ_UINT32 * p_data_read, - OPJ_UINT32 p_max_length, - opj_packet_info_t *pack_info, + opj_packet_info_t *pack_info, opj_event_mgr_t* p_manager) { OPJ_UINT32 bandno, cblkno; OPJ_UINT32 l_nb_code_blocks; - OPJ_BYTE *l_current_data = p_src_data; opj_tcd_band_t *l_band = 00; opj_tcd_cblk_dec_t* l_cblk = 00; opj_tcd_resolution_t* l_res = &p_tile->comps[p_pi->compno].resolutions[p_pi->resno]; @@ -1155,10 +1400,12 @@ static OPJ_BOOL opj_t2_read_packet_data( opj_t2_t* p_t2, } do { + OPJ_OFF_T offset = opj_seg_buf_get_global_offset(src_buf); + OPJ_SIZE_T len = src_buf->data_len; /* Check possible overflow (on l_current_data only, assumes input args already checked) then size */ - if ((((OPJ_SIZE_T)l_current_data + (OPJ_SIZE_T)l_seg->newlen) < (OPJ_SIZE_T)l_current_data) || (l_current_data + l_seg->newlen > p_src_data + p_max_length)) { + if ((((OPJ_SIZE_T)offset + (OPJ_SIZE_T)l_seg->newlen) > (OPJ_SIZE_T)len)) { opj_event_msg(p_manager, EVT_ERROR, "read: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", - l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno, p_pi->compno); + l_seg->newlen, len, cblkno, p_pi->precno, bandno, p_pi->resno, p_pi->compno); return OPJ_FALSE; } @@ -1187,6 +1434,7 @@ static OPJ_BOOL opj_t2_read_packet_data( opj_t2_t* p_t2, l_seg->newlen, l_cblk->data_current_size, 0xFFFFFFFF - l_seg->newlen, cblkno, p_pi->precno, bandno, p_pi->resno, p_pi->compno); return OPJ_FALSE; } +#ifdef POO /* Check if the cblk->data have allocated enough memory */ if ((l_cblk->data_current_size + l_seg->newlen) > l_cblk->data_max_size) { OPJ_BYTE* new_cblk_data = (OPJ_BYTE*) opj_realloc(l_cblk->data, l_cblk->data_current_size + l_seg->newlen); @@ -1201,15 +1449,19 @@ static OPJ_BOOL opj_t2_read_packet_data( opj_t2_t* p_t2, l_cblk->data = new_cblk_data; } - memcpy(l_cblk->data + l_cblk->data_current_size, l_current_data, l_seg->newlen); - + memcpy(l_cblk->data + l_cblk->data_current_size, src_buf->mother.buf + src_buf->mother.offset, l_seg->newlen); +#endif if (l_seg->numpasses == 0) { - l_seg->data = &l_cblk->data; - l_seg->dataindex = l_cblk->data_current_size; + l_seg->dataindex = l_cblk->data_current_size; } - l_current_data += l_seg->newlen; - l_seg->numpasses += l_seg->numnewpasses; + opj_min_buf_vec_push_back(&l_cblk->seg_buffers, opj_seg_buf_get_global_ptr(src_buf), (OPJ_UINT16)l_seg->newlen); + + + + *(p_data_read) += l_seg->newlen; + opj_seg_buf_incr_cur_seg_offset(src_buf, l_seg->newlen); + l_seg->numpasses += l_seg->numnewpasses; l_cblk->numnewpasses -= l_seg->numnewpasses; l_seg->real_num_passes = l_seg->numpasses; @@ -1228,10 +1480,6 @@ static OPJ_BOOL opj_t2_read_packet_data( opj_t2_t* p_t2, ++l_band; } - - *(p_data_read) = (OPJ_UINT32)(l_current_data - p_src_data); - - return OPJ_TRUE; } diff --git a/src/lib/openjp2/t2.h b/src/lib/openjp2/t2.h index 3b652eeab..38dff38eb 100644 --- a/src/lib/openjp2/t2.h +++ b/src/lib/openjp2/t2.h @@ -75,7 +75,6 @@ Encode the packets of a tile to a destination buffer @param tpnum Tile part number of the current tile @param tppos The position of the tile part flag in the progression order @param pino FIXME DOC -@param t2_mode If == 0 In Threshold calculation ,If == 1 Final pass */ OPJ_BOOL opj_t2_encode_packets( opj_t2_t* t2, OPJ_UINT32 tileno, @@ -87,8 +86,26 @@ OPJ_BOOL opj_t2_encode_packets( opj_t2_t* t2, opj_codestream_info_t *cstr_info, OPJ_UINT32 tpnum, OPJ_INT32 tppos, - OPJ_UINT32 pino, - J2K_T2_MODE t2_mode); + OPJ_UINT32 pino); + +/** +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 p_data_written FIXME DOC +@param len the length of the destination buffer +@param tppos The position of the tile part flag in the progression order +*/ +OPJ_BOOL opj_t2_encode_packets_thresh(opj_t2_t* t2, + OPJ_UINT32 tileno, + opj_tcd_tile_t *tile, + OPJ_UINT32 maxlayers, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 len, + OPJ_INT32 tppos); + /** Decode the packets of a tile from a source buffer @@ -105,9 +122,8 @@ Decode the packets of a tile from a source buffer OPJ_BOOL opj_t2_decode_packets( opj_t2_t *t2, OPJ_UINT32 tileno, opj_tcd_tile_t *tile, - OPJ_BYTE *src, + opj_seg_buf_t* src_buf, OPJ_UINT32 * p_data_read, - OPJ_UINT32 len, opj_codestream_index_t *cstr_info, opj_event_mgr_t *p_manager); diff --git a/src/lib/openjp2/tcd.c b/src/lib/openjp2/tcd.c index 6eeb211e2..36fc13fac 100644 --- a/src/lib/openjp2/tcd.c +++ b/src/lib/openjp2/tcd.c @@ -39,6 +39,10 @@ */ #include "opj_includes.h" +#ifdef _OPENMP +#include +#endif + /* ----------------------------------------------------------------------- */ @@ -110,7 +114,7 @@ void tcd_dump(FILE *fd, opj_tcd_t *tcd, opj_tcd_image_t * img) { static INLINE OPJ_BOOL opj_tcd_init_tile(opj_tcd_t *p_tcd, OPJ_UINT32 p_tile_no, OPJ_BOOL isEncoder, OPJ_FLOAT32 fraction, OPJ_SIZE_T sizeof_block, opj_event_mgr_t* manager); /** -* Allocates memory for a decoding code block. +* Allocates memory for a decoding code block (but not data) */ static OPJ_BOOL opj_tcd_code_block_dec_allocate (opj_tcd_cblk_dec_t * p_code_block); @@ -143,9 +147,8 @@ static void opj_tcd_free_tile(opj_tcd_t *tcd); static OPJ_BOOL opj_tcd_t2_decode ( opj_tcd_t *p_tcd, - OPJ_BYTE * p_src_data, + opj_seg_buf_t* src_buf, OPJ_UINT32 * p_data_read, - OPJ_UINT32 p_max_src_size, opj_codestream_index_t *p_cstr_index, opj_event_mgr_t *p_manager); @@ -173,9 +176,8 @@ static OPJ_BOOL opj_tcd_t2_encode ( opj_tcd_t *p_tcd, opj_codestream_info_t *p_cstr_info ); static OPJ_BOOL opj_tcd_rate_allocate_encode( opj_tcd_t *p_tcd, - OPJ_BYTE * p_dest_data, - OPJ_UINT32 p_max_dest_size, - opj_codestream_info_t *p_cstr_info ); + OPJ_UINT32 p_max_dest_size, + opj_codestream_info_t *p_cstr_info ); /* ----------------------------------------------------------------------- */ @@ -228,20 +230,20 @@ void opj_tcd_makelayer( opj_tcd_t *tcd, tcd_tile->distolayer[layno] = 0; /* fixed_quality */ for (compno = 0; compno < tcd_tile->numcomps; compno++) { - opj_tcd_tilecomp_t *tilec = &tcd_tile->comps[compno]; + opj_tcd_tilecomp_t *tilec = tcd_tile->comps+compno; for (resno = 0; resno < tilec->numresolutions; resno++) { - opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + opj_tcd_resolution_t *res = tilec->resolutions+resno; for (bandno = 0; bandno < res->numbands; bandno++) { - opj_tcd_band_t *band = &res->bands[bandno]; + opj_tcd_band_t *band = res->bands+bandno; for (precno = 0; precno < res->pw * res->ph; precno++) { - opj_tcd_precinct_t *prc = &band->precincts[precno]; + opj_tcd_precinct_t *prc = band->precincts+precno; for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { - opj_tcd_cblk_enc_t *cblk = &prc->cblks.enc[cblkno]; - opj_tcd_layer_t *layer = &cblk->layers[layno]; + opj_tcd_cblk_enc_t *cblk = prc->cblks.enc+cblkno; + opj_tcd_layer_t *layer = cblk->layers+layno; OPJ_UINT32 n; if (layno == 0) { @@ -394,7 +396,6 @@ void opj_tcd_makelayer_fixed(opj_tcd_t *tcd, OPJ_UINT32 layno, OPJ_UINT32 final) } OPJ_BOOL opj_tcd_rateallocate( opj_tcd_t *tcd, - OPJ_BYTE *dest, OPJ_UINT32 * p_data_written, OPJ_UINT32 len, opj_codestream_info_t *cstr_info) @@ -490,6 +491,7 @@ OPJ_BOOL opj_tcd_rateallocate( opj_tcd_t *tcd, OPJ_UINT32 maxlen = tcd_tcp->rates[layno] ? opj_uint_min(((OPJ_UINT32) ceil(tcd_tcp->rates[layno])), len) : len; OPJ_FLOAT64 goodthresh = 0; OPJ_FLOAT64 stable_thresh = 0; + OPJ_FLOAT64 old_thresh = -1; OPJ_UINT32 i; OPJ_FLOAT64 distotarget; /* fixed_quality */ @@ -514,10 +516,13 @@ OPJ_BOOL opj_tcd_rateallocate( opj_tcd_t *tcd, thresh = (lo + hi) / 2; opj_tcd_makelayer(tcd, layno, thresh, 0); + if ((fabs(old_thresh - thresh)) < 0.001) + break; + old_thresh = thresh; if (cp->m_specific_param.m_enc.m_fixed_quality) { /* fixed_quality */ if(OPJ_IS_CINEMA(cp->rsiz)){ - if (! opj_t2_encode_packets(t2,tcd->tcd_tileno, tcd_tile, layno + 1, dest, p_data_written, maxlen, cstr_info,tcd->cur_tp_num,tcd->tp_pos,tcd->cur_pino,THRESH_CALC)) { + if (! opj_t2_encode_packets_thresh(t2,tcd->tcd_tileno, tcd_tile, layno + 1, p_data_written, maxlen, tcd->tp_pos)) { lo = thresh; continue; @@ -546,7 +551,7 @@ OPJ_BOOL opj_tcd_rateallocate( opj_tcd_t *tcd, lo = thresh; } } else { - if (! opj_t2_encode_packets(t2, tcd->tcd_tileno, tcd_tile, layno + 1, dest,p_data_written, maxlen, cstr_info,tcd->cur_tp_num,tcd->tp_pos,tcd->cur_pino,THRESH_CALC)) + if (! opj_t2_encode_packets_thresh(t2, tcd->tcd_tileno, tcd_tile, layno + 1, p_data_written, maxlen, tcd->tp_pos)) { /* TODO: what to do with l ??? seek / tell ??? */ /* opj_event_msg(tcd->cinfo, EVT_INFO, "rate alloc: len=%d, max=%d\n", l, maxlen); */ @@ -695,6 +700,8 @@ static INLINE OPJ_BOOL opj_tcd_init_tile(opj_tcd_t *p_tcd, OPJ_UINT32 p_tile_no, l_image = p_tcd->image; l_image_comp = p_tcd->image->comps; + opj_seg_buf_rewind(&l_tcp->m_data); + p = p_tile_no % l_cp->tw; /* tile coordinates */ q = p_tile_no / l_cp->tw; /*fprintf(stderr, "Tile coordinate = %d,%d\n", p, q);*/ @@ -1091,44 +1098,41 @@ static OPJ_BOOL opj_tcd_code_block_enc_allocate_data (opj_tcd_cblk_enc_t * p_cod } /** - * Allocates memory for a decoding code block. + * Allocates memory for a decoding code block (but not data) */ static OPJ_BOOL opj_tcd_code_block_dec_allocate (opj_tcd_cblk_dec_t * p_code_block) { - if (! p_code_block->data) { - - p_code_block->data = (OPJ_BYTE*) opj_malloc(OPJ_J2K_DEFAULT_CBLK_DATA_SIZE); - if (! p_code_block->data) { - return OPJ_FALSE; - } - p_code_block->data_max_size = OPJ_J2K_DEFAULT_CBLK_DATA_SIZE; - /*fprintf(stderr, "Allocate 8192 elements of code_block->data\n");*/ + if (!p_code_block->segs) { + p_code_block->segs = (opj_tcd_seg_t *)opj_calloc(OPJ_J2K_DEFAULT_NB_SEGS, sizeof(opj_tcd_seg_t)); + if (!p_code_block->segs) { + return OPJ_FALSE; + } + /*fprintf(stderr, "Allocate %d elements of code_block->data\n", OPJ_J2K_DEFAULT_NB_SEGS * sizeof(opj_tcd_seg_t));*/ - p_code_block->segs = (opj_tcd_seg_t *) opj_calloc(OPJ_J2K_DEFAULT_NB_SEGS,sizeof(opj_tcd_seg_t)); - if (! p_code_block->segs) { - return OPJ_FALSE; - } - /*fprintf(stderr, "Allocate %d elements of code_block->data\n", OPJ_J2K_DEFAULT_NB_SEGS * sizeof(opj_tcd_seg_t));*/ - - p_code_block->m_current_max_segs = OPJ_J2K_DEFAULT_NB_SEGS; - /*fprintf(stderr, "m_current_max_segs of code_block->data = %d\n", p_code_block->m_current_max_segs);*/ - } else { - /* sanitize */ - OPJ_BYTE* l_data = p_code_block->data; - OPJ_UINT32 l_data_max_size = p_code_block->data_max_size; - opj_tcd_seg_t * l_segs = p_code_block->segs; - OPJ_UINT32 l_current_max_segs = p_code_block->m_current_max_segs; - - memset(p_code_block, 0, sizeof(opj_tcd_cblk_dec_t)); - p_code_block->data = l_data; - p_code_block->data_max_size = l_data_max_size; - p_code_block->segs = l_segs; - p_code_block->m_current_max_segs = l_current_max_segs; - } + p_code_block->m_current_max_segs = OPJ_J2K_DEFAULT_NB_SEGS; - return OPJ_TRUE; + /*fprintf(stderr, "Allocate 8192 elements of code_block->data\n");*/ + /*fprintf(stderr, "m_current_max_segs of code_block->data = %d\n", p_code_block->m_current_max_segs);*/ + } + else { + /* sanitize */ + opj_tcd_seg_t * l_segs = p_code_block->segs; + OPJ_UINT32 l_current_max_segs = p_code_block->m_current_max_segs; + + /* Note: since seg_buffers simply holds references to another data buffer, + we do not need to copy it to the sanitized block */ + opj_vec_cleanup(&p_code_block->seg_buffers); + + memset(p_code_block, 0, sizeof(opj_tcd_cblk_dec_t)); + p_code_block->segs = l_segs; + p_code_block->m_current_max_segs = l_current_max_segs; + } + return OPJ_TRUE; } - +/* +Get size of tile data, summed over all components, reflecting actual precision of data. +opj_image_t always stores data in 32 bit format. +*/ OPJ_UINT32 opj_tcd_get_decoded_tile_size ( opj_tcd_t *p_tcd ) { OPJ_UINT32 i; @@ -1136,18 +1140,13 @@ OPJ_UINT32 opj_tcd_get_decoded_tile_size ( opj_tcd_t *p_tcd ) opj_image_comp_t * l_img_comp = 00; opj_tcd_tilecomp_t * l_tile_comp = 00; opj_tcd_resolution_t * l_res = 00; - OPJ_UINT32 l_size_comp, l_remaining; + OPJ_UINT32 l_size_comp; 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; - } + l_size_comp = (l_img_comp->prec + 7) >> 3; if (l_size_comp == 3) { l_size_comp = 4; @@ -1226,7 +1225,7 @@ OPJ_BOOL opj_tcd_encode_tile( opj_tcd_t *p_tcd, /* FIXME _ProfStop(PGROUP_T1); */ /* FIXME _ProfStart(PGROUP_RATE); */ - if (! opj_tcd_rate_allocate_encode(p_tcd,p_dest,p_max_length,p_cstr_info)) { + if (! opj_tcd_rate_allocate_encode(p_tcd,p_max_length,p_cstr_info)) { return OPJ_FALSE; } /* FIXME _ProfStop(PGROUP_RATE); */ @@ -1251,8 +1250,7 @@ OPJ_BOOL opj_tcd_encode_tile( opj_tcd_t *p_tcd, } OPJ_BOOL opj_tcd_decode_tile( opj_tcd_t *p_tcd, - OPJ_BYTE *p_src, - OPJ_UINT32 p_max_length, + opj_seg_buf_t* src_buf, OPJ_UINT32 p_tile_no, opj_codestream_index_t *p_cstr_index, opj_event_mgr_t *p_manager @@ -1288,7 +1286,7 @@ OPJ_BOOL opj_tcd_decode_tile( opj_tcd_t *p_tcd, /*--------------TIER2------------------*/ /* FIXME _ProfStart(PGROUP_T2); */ l_data_read = 0; - if (! opj_tcd_t2_decode(p_tcd, p_src, &l_data_read, p_max_length, p_cstr_index, p_manager)) + if (! opj_tcd_t2_decode(p_tcd, src_buf, &l_data_read,p_cstr_index, p_manager)) { return OPJ_FALSE; } @@ -1336,6 +1334,20 @@ OPJ_BOOL opj_tcd_decode_tile( opj_tcd_t *p_tcd, return OPJ_TRUE; } +/* + +For each component, copy decoded resolutions from the tile data buffer +into p_dest buffer. + +So, p_dest stores a sub-region of the tcd data, based on the number +of resolutions decoded. (why doesn't tile data buffer also match number of resolutions decoded ?) + +Note: p_dest stores data in the actual precision of the decompressed image, +vs. tile data buffer which is always 32 bits. + +If we are decoding all resolutions, then this step is not necessary ?? + +*/ OPJ_BOOL opj_tcd_update_tile_data ( opj_tcd_t *p_tcd, OPJ_BYTE * p_dest, OPJ_UINT32 p_dest_length @@ -1345,7 +1357,7 @@ OPJ_BOOL opj_tcd_update_tile_data ( opj_tcd_t *p_tcd, opj_image_comp_t * l_img_comp = 00; opj_tcd_tilecomp_t * l_tilec = 00; opj_tcd_resolution_t * l_res; - OPJ_UINT32 l_size_comp, l_remaining; + OPJ_UINT32 l_size_comp; OPJ_UINT32 l_stride, l_width,l_height; l_data_size = opj_tcd_get_decoded_tile_size(p_tcd); @@ -1357,17 +1369,12 @@ OPJ_BOOL opj_tcd_update_tile_data ( opj_tcd_t *p_tcd, 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_size_comp = (l_img_comp->prec + 7) >> 3; l_res = l_tilec->resolutions + l_img_comp->resno_decoded; l_width = (OPJ_UINT32)(l_res->x1 - l_res->x0); l_height = (OPJ_UINT32)(l_res->y1 - l_res->y0); l_stride = (OPJ_UINT32)(l_tilec->x1 - l_tilec->x0) - l_width; - if (l_remaining) { - ++l_size_comp; - } - if (l_size_comp == 3) { l_size_comp = 4; } @@ -1535,9 +1542,8 @@ static void opj_tcd_free_tile(opj_tcd_t *p_tcd) static OPJ_BOOL opj_tcd_t2_decode (opj_tcd_t *p_tcd, - OPJ_BYTE * p_src_data, + opj_seg_buf_t* src_buf, OPJ_UINT32 * p_data_read, - OPJ_UINT32 p_max_src_size, opj_codestream_index_t *p_cstr_index, opj_event_mgr_t *p_manager ) @@ -1553,9 +1559,8 @@ static OPJ_BOOL opj_tcd_t2_decode (opj_tcd_t *p_tcd, l_t2, p_tcd->tcd_tileno, p_tcd->tcd_image->tiles, - p_src_data, + src_buf, p_data_read, - p_max_src_size, p_cstr_index, p_manager)) { opj_t2_destroy(l_t2); @@ -1571,42 +1576,36 @@ static OPJ_BOOL opj_tcd_t2_decode (opj_tcd_t *p_tcd, static OPJ_BOOL opj_tcd_t1_decode ( opj_tcd_t *p_tcd ) { OPJ_UINT32 compno; - opj_t1_t * l_t1; opj_tcd_tile_t * l_tile = p_tcd->tcd_image->tiles; opj_tcd_tilecomp_t* l_tile_comp = l_tile->comps; opj_tccp_t * l_tccp = p_tcd->tcp->tccps; - - - l_t1 = opj_t1_create(OPJ_FALSE); - if (l_t1 == 00) { - return OPJ_FALSE; - } - for (compno = 0; compno < l_tile->numcomps; ++compno) { + /* The +3 is headroom required by the vectorized DWT */ - if (OPJ_FALSE == opj_t1_decode_cblks(l_t1, l_tile_comp, l_tccp)) { - opj_t1_destroy(l_t1); + if (OPJ_FALSE == opj_t1_decode_cblks(l_tile_comp, l_tccp)) { return OPJ_FALSE; } ++l_tile_comp; ++l_tccp; } - - opj_t1_destroy(l_t1); - return OPJ_TRUE; } static OPJ_BOOL opj_tcd_dwt_decode ( opj_tcd_t *p_tcd ) { - OPJ_UINT32 compno; opj_tcd_tile_t * l_tile = p_tcd->tcd_image->tiles; - opj_tcd_tilecomp_t * l_tile_comp = l_tile->comps; - opj_tccp_t * l_tccp = p_tcd->tcp->tccps; - opj_image_comp_t * l_img_comp = p_tcd->image->comps; - - for (compno = 0; compno < l_tile->numcomps; compno++) { + OPJ_INT64 compno; + OPJ_BOOL rc = OPJ_TRUE; +#ifdef _OPENMP + #pragma omp parallel default(none) private(compno) shared(p_tcd, l_tile, rc) + { + #pragma omp for +#endif + for (compno = 0; compno < (OPJ_INT64)l_tile->numcomps; compno++) { + opj_tcd_tilecomp_t * l_tile_comp = l_tile->comps + compno; + opj_tccp_t * l_tccp = p_tcd->tcp->tccps + compno; + opj_image_comp_t * l_img_comp = p_tcd->image->comps + compno; /* if (tcd->cp->reduce != 0) { tcd->image->comps[compno].resno_decoded = @@ -1622,21 +1621,23 @@ static OPJ_BOOL opj_tcd_dwt_decode ( opj_tcd_t *p_tcd ) if (l_tccp->qmfbid == 1) { if (! opj_dwt_decode(l_tile_comp, l_img_comp->resno_decoded+1)) { - return OPJ_FALSE; + rc = OPJ_FALSE; + continue; } } else { if (! opj_dwt_decode_real(l_tile_comp, l_img_comp->resno_decoded+1)) { - return OPJ_FALSE; + rc = OPJ_FALSE; + continue; } } +#ifdef _OPENMP + } +#endif - ++l_tile_comp; - ++l_img_comp; - ++l_tccp; - } + } - return OPJ_TRUE; + return rc; } static OPJ_BOOL opj_tcd_mct_decode ( opj_tcd_t *p_tcd, opj_event_mgr_t *p_manager) { @@ -1718,22 +1719,20 @@ static OPJ_BOOL opj_tcd_mct_decode ( opj_tcd_t *p_tcd, opj_event_mgr_t *p_manage static OPJ_BOOL opj_tcd_dc_level_shift_decode ( opj_tcd_t *p_tcd ) { OPJ_UINT32 compno; - opj_tcd_tilecomp_t * l_tile_comp = 00; - opj_tccp_t * l_tccp = 00; - opj_image_comp_t * l_img_comp = 00; opj_tcd_resolution_t* l_res = 00; - opj_tcd_tile_t * l_tile; OPJ_UINT32 l_width,l_height,i,j; OPJ_INT32 * l_current_ptr; OPJ_INT32 l_min, l_max; OPJ_UINT32 l_stride; - l_tile = p_tcd->tcd_image->tiles; - l_tile_comp = l_tile->comps; - l_tccp = p_tcd->tcp->tccps; - l_img_comp = p_tcd->image->comps; + opj_tcd_tile_t *l_tile = p_tcd->tcd_image->tiles; + for (compno = 0; compno < l_tile->numcomps; compno++) { + opj_tcd_tilecomp_t *l_tile_comp = l_tile->comps + compno; + opj_tccp_t * l_tccp = p_tcd->tcp->tccps + compno; + opj_image_comp_t * l_img_comp = p_tcd->image->comps + compno; + l_res = l_tile_comp->resolutions + l_img_comp->resno_decoded; l_width = (OPJ_UINT32)(l_res->x1 - l_res->x0); l_height = (OPJ_UINT32)(l_res->y1 - l_res->y0); @@ -1771,10 +1770,6 @@ static OPJ_BOOL opj_tcd_dc_level_shift_decode ( opj_tcd_t *p_tcd ) l_current_ptr += l_stride; } } - - ++l_img_comp; - ++l_tccp; - ++l_tile_comp; } return OPJ_TRUE; @@ -1801,12 +1796,7 @@ static void opj_tcd_code_block_dec_deallocate (opj_tcd_precinct_t * p_precinct) /*fprintf(stderr,"nb_code_blocks =%d\t}\n", l_nb_code_blocks);*/ for (cblkno = 0; cblkno < l_nb_code_blocks; ++cblkno) { - - if (l_code_block->data) { - opj_free(l_code_block->data); - l_code_block->data = 00; - } - + opj_vec_cleanup(&l_code_block->seg_buffers); if (l_code_block->segs) { opj_free(l_code_block->segs ); l_code_block->segs = 00; @@ -1979,44 +1969,46 @@ static OPJ_BOOL opj_tcd_mct_encode ( opj_tcd_t *p_tcd ) return OPJ_TRUE; } -static OPJ_BOOL opj_tcd_dwt_encode ( opj_tcd_t *p_tcd ) -{ - opj_tcd_tile_t * l_tile = p_tcd->tcd_image->tiles; - opj_tcd_tilecomp_t * l_tile_comp = p_tcd->tcd_image->tiles->comps; - opj_tccp_t * l_tccp = p_tcd->tcp->tccps; - OPJ_UINT32 compno; - for (compno = 0; compno < l_tile->numcomps; ++compno) { +OPJ_BOOL opj_tcd_dwt_encode ( opj_tcd_t *p_tcd ) +{ + opj_tcd_tile_t * l_tile = p_tcd->tcd_image->tiles; + OPJ_INT64 compno; + OPJ_BOOL rc = OPJ_TRUE; +#ifdef _OPENMP + #pragma omp parallel default(none) private(compno) shared(p_tcd, l_tile, rc) + { + #pragma omp for +#endif + for (compno = 0; compno < (OPJ_INT64)l_tile->numcomps; ++compno) { + opj_tcd_tilecomp_t * tile_comp = p_tcd->tcd_image->tiles->comps + compno; + opj_tccp_t * l_tccp = p_tcd->tcp->tccps + compno; if (l_tccp->qmfbid == 1) { - if (! opj_dwt_encode(l_tile_comp)) { - return OPJ_FALSE; + if (! opj_dwt_encode(tile_comp)) { + rc = OPJ_FALSE; + continue; } } else if (l_tccp->qmfbid == 0) { - if (! opj_dwt_encode_real(l_tile_comp)) { - return OPJ_FALSE; + if (! opj_dwt_encode_real(tile_comp)) { + rc = OPJ_FALSE; + continue; } } - - ++l_tile_comp; - ++l_tccp; } - - return OPJ_TRUE; +#ifdef _OPENMP + } +#endif + + return rc; } static OPJ_BOOL opj_tcd_t1_encode ( opj_tcd_t *p_tcd ) { - opj_t1_t * l_t1; const OPJ_FLOAT64 * l_mct_norms; OPJ_UINT32 l_mct_numcomps = 0U; opj_tcp_t * l_tcp = p_tcd->tcp; - l_t1 = opj_t1_create(OPJ_TRUE); - if (l_t1 == 00) { - return OPJ_FALSE; - } - if (l_tcp->mct == 1) { l_mct_numcomps = 3U; /* irreversible encoding */ @@ -2032,14 +2024,7 @@ static OPJ_BOOL opj_tcd_t1_encode ( opj_tcd_t *p_tcd ) l_mct_norms = (const OPJ_FLOAT64 *) (l_tcp->mct_norms); } - if (! opj_t1_encode_cblks(l_t1, p_tcd->tcd_image->tiles , l_tcp, l_mct_norms, l_mct_numcomps)) { - opj_t1_destroy(l_t1); - return OPJ_FALSE; - } - - opj_t1_destroy(l_t1); - - return OPJ_TRUE; + return opj_t1_encode_cblks(p_tcd->tcd_image->tiles, l_tcp, l_mct_norms, l_mct_numcomps); } static OPJ_BOOL opj_tcd_t2_encode (opj_tcd_t *p_tcd, @@ -2066,8 +2051,7 @@ static OPJ_BOOL opj_tcd_t2_encode (opj_tcd_t *p_tcd, p_cstr_info, p_tcd->tp_num, p_tcd->tp_pos, - p_tcd->cur_pino, - FINAL_PASS)) + p_tcd->cur_pino)) { opj_t2_destroy(l_t2); return OPJ_FALSE; @@ -2081,9 +2065,8 @@ static OPJ_BOOL opj_tcd_t2_encode (opj_tcd_t *p_tcd, static OPJ_BOOL opj_tcd_rate_allocate_encode( opj_tcd_t *p_tcd, - OPJ_BYTE * p_dest_data, - OPJ_UINT32 p_max_dest_size, - opj_codestream_info_t *p_cstr_info ) + OPJ_UINT32 p_max_dest_size, + opj_codestream_info_t *p_cstr_info ) { opj_cp_t * l_cp = p_tcd->cp; OPJ_UINT32 l_nb_written = 0; @@ -2095,7 +2078,7 @@ static OPJ_BOOL opj_tcd_rate_allocate_encode( opj_tcd_t *p_tcd, 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 (! opj_tcd_rateallocate(p_tcd, p_dest_data,&l_nb_written, p_max_dest_size, p_cstr_info)) { + if (! opj_tcd_rateallocate(p_tcd, &l_nb_written, p_max_dest_size, p_cstr_info)) { return OPJ_FALSE; } } diff --git a/src/lib/openjp2/tcd.h b/src/lib/openjp2/tcd.h index 07f8379af..7defaae2a 100644 --- a/src/lib/openjp2/tcd.h +++ b/src/lib/openjp2/tcd.h @@ -53,7 +53,6 @@ each other. The functions in TCD.C are used by other functions in J2K.C. FIXME DOC */ typedef struct opj_tcd_seg { - OPJ_BYTE ** data; OPJ_UINT32 dataindex; OPJ_UINT32 numpasses; OPJ_UINT32 real_num_passes; @@ -101,7 +100,7 @@ typedef struct opj_tcd_cblk_enc { typedef struct opj_tcd_cblk_dec { - OPJ_BYTE * data; /* Data */ + opj_vec_t seg_buffers; opj_tcd_seg_t* segs; /* segments information */ OPJ_INT32 x0, y0, x1, y1; /* position of the code-blocks : left upper corner (x0, y0) right low corner (x1,y1) */ OPJ_UINT32 numbps; @@ -278,7 +277,6 @@ void opj_tcd_makelayer( opj_tcd_t *tcd, OPJ_UINT32 final); OPJ_BOOL opj_tcd_rateallocate( opj_tcd_t *tcd, - OPJ_BYTE *dest, OPJ_UINT32 * p_data_written, OPJ_UINT32 len, opj_codestream_info_t *cstr_info); @@ -316,8 +314,7 @@ Decode a tile from a buffer into a raw image @param manager the event manager. */ OPJ_BOOL opj_tcd_decode_tile( opj_tcd_t *tcd, - OPJ_BYTE *src, - OPJ_UINT32 len, + opj_seg_buf_t* src_buf, OPJ_UINT32 tileno, opj_codestream_index_t *cstr_info, opj_event_mgr_t *manager); diff --git a/src/lib/openjp2/vector.c b/src/lib/openjp2/vector.c new file mode 100644 index 000000000..faaa48dbf --- /dev/null +++ b/src/lib/openjp2/vector.c @@ -0,0 +1,117 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2002-2016, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2016, OpenJPEG contributors + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opj_includes.h" + +const OPJ_INT32 VECTOR_INITIAL_CAPACITY = 4; + + +static OPJ_BOOL opj_vec_double_capacity_if_full(opj_vec_t *vec) { + if (!vec) + return OPJ_FALSE; + if (vec->size == vec->capacity-1) { + void** new_data = NULL; + OPJ_INT32 new_capacity = (OPJ_INT32)(1.5*vec->capacity); + new_data = opj_realloc(vec->data, sizeof(void*) * (OPJ_SIZE_T)new_capacity); + if (new_data) { + vec->capacity = new_capacity; + vec->data = new_data; + return OPJ_TRUE; + } + else { + return OPJ_FALSE; + } + } + return OPJ_TRUE; +} + +OPJ_BOOL opj_vec_init(opj_vec_t *vec) { + if (!vec) + return OPJ_FALSE; + if (vec->data) + return OPJ_TRUE; + + vec->size = 0; + vec->capacity = VECTOR_INITIAL_CAPACITY; + vec->data = opj_malloc(sizeof(void*) * (OPJ_SIZE_T)vec->capacity); + return vec->data ? OPJ_TRUE : OPJ_FALSE; +} + +OPJ_BOOL opj_vec_push_back(opj_vec_t *vec, void* value) { + if (!opj_vec_double_capacity_if_full(vec)) + return OPJ_FALSE; + vec->data[vec->size++] = value; + return OPJ_TRUE; +} + +void* opj_vec_get(opj_vec_t *vec, OPJ_INT32 index) { + if (!vec->data) + return NULL; + assert(index < vec->size && index >= 0); + if (index >= vec->size || index < 0) { + return NULL; + } + return vec->data[index]; +} + +void* opj_vec_back(opj_vec_t *vec) { + if (!vec || !vec->data || !vec->size) + return NULL; + return opj_vec_get(vec, vec->size - 1); +} + +OPJ_BOOL opj_vec_set(opj_vec_t *vec, OPJ_INT32 index, void* value) { + if (!vec) + return OPJ_FALSE; + while (index >= vec->size) { + if (!opj_vec_push_back(vec, NULL)) + return OPJ_FALSE; + } + vec->data[index] = value; + return OPJ_TRUE; +} + +void opj_vec_cleanup(opj_vec_t *vec) { + OPJ_INT32 i; + if (!vec || !vec->data) + return; + + if (vec->owns_data) { + for (i = 0; i < vec->size; ++i) { + if (vec->data[i]) + opj_free(vec->data[i]); + } + } + opj_free(vec->data); + vec->data = NULL; + vec->size = 0; +} \ No newline at end of file diff --git a/src/lib/openjp2/vector.h b/src/lib/openjp2/vector.h new file mode 100644 index 000000000..b3ec99bc2 --- /dev/null +++ b/src/lib/openjp2/vector.h @@ -0,0 +1,79 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2002-2016, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2016, OpenJPEG contributors + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __VECTOR_H +#define __VECTOR_H + +/* +Vector - a dynamic array. + +*/ + +typedef struct opj_vec{ + OPJ_INT32 size; /* current size of vec */ + OPJ_INT32 capacity; /* maximum size of vec */ + void* *data; /* array of void* pointers */ + OPJ_BOOL owns_data; +} opj_vec_t; + +/* +Initialize vector +*/ +OPJ_BOOL opj_vec_init(opj_vec_t *vec); + +/* +Add a value to the end of the vector +*/ +OPJ_BOOL opj_vec_push_back(opj_vec_t *vec, void* value); + +/* +Set a value at specified index. If index is greater then the size of the vector, +all intervening indices will be initialized to NULL +*/ +OPJ_BOOL opj_vec_set(opj_vec_t *vec, OPJ_INT32 index, void* value); + +/* +Get value at specified index +*/ +void* opj_vec_get(opj_vec_t *vec, OPJ_INT32 index); + +/* +Get value at end of vector +*/ +void* opj_vec_back(opj_vec_t *vec); + +/* +Clean up vector resources. Does NOT free vector itself +*/ +void opj_vec_cleanup(opj_vec_t *vec); + +#endif \ No newline at end of file