From fcfb8dd2ed6c86513f86e941e81b610e6957fff1 Mon Sep 17 00:00:00 2001 From: Mickael Savinaud Date: Fri, 9 Mar 2012 17:15:41 +0000 Subject: [PATCH] [trunk] first steps about merge compression WIP --- applications/codec/image_to_j2k.c | 259 +++++++++++++++++++++--------- libopenjpeg/j2k.c | 111 +++++++++++++ libopenjpeg/j2k.h | 16 ++ libopenjpeg/openjpeg.c | 96 +++++++++++ libopenjpeg/openjpeg.h | 35 +++- 5 files changed, 444 insertions(+), 73 deletions(-) diff --git a/applications/codec/image_to_j2k.c b/applications/codec/image_to_j2k.c index cbdc1e60..fdb85025 100644 --- a/applications/codec/image_to_j2k.c +++ b/applications/codec/image_to_j2k.c @@ -6,6 +6,7 @@ * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe * Copyright (c) 2005, Herve Drolon, FreeImage Team * Copyright (c) 2006-2007, Parvatha Elangovan + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -211,6 +212,8 @@ void encode_help_display(void) { fprintf(stdout," -F rawWidth,rawHeight,rawComp,rawBitDepth,s/u (Signed/Unsigned)\n"); fprintf(stdout," Example: -i lena.raw -o lena.j2k -F 512,512,3,8,u\n"); fprintf(stdout,"\n"); + fprintf(stdout,"-m : use array-based MCT, values are coma separated, line by line\n"); + fprintf(stdout," no specific separators between lines, no space allowed between values\n"); fprintf(stdout,"-jpip : write jpip codestream index box in JP2 output file\n"); fprintf(stdout," NOTICE: currently supports only RPCL order\n"); fprintf(stdout,"\n"); @@ -1054,6 +1057,73 @@ int parse_cmdline_encoder(int argc, char **argv, opj_cparameters_t *parameters, } break; + /* ------------------------------------------------------ */ + case 'm': /* mct input file */ + { + char *lFilename = opj_optarg; + char *lMatrix; + char *lCurrentPtr ; + float *lCurrentDoublePtr; + float *lSpace; + int *l_int_ptr; + int lNbComp = 0, lTotalComp, lMctComp, i, lStrLen; + + /* Open file */ + FILE * lFile = fopen(lFilename,"r"); + if (lFile == NULL) { + return 1; + } + + /* Set size of file and read its content*/ + fseek(lFile,0,SEEK_END); + lStrLen = ftell(lFile); + fseek(lFile,0,SEEK_SET); + lMatrix = (char *) malloc(lStrLen + 1); + fread(lMatrix, lStrLen, 1, lFile); + fclose(lFile); + + lMatrix[lStrLen] = 0; + lCurrentPtr = lMatrix; + + /* replace ',' by 0 */ + while (*lCurrentPtr != 0 ) { + if (*lCurrentPtr == ' ') { + *lCurrentPtr = 0; + ++lNbComp; + } + ++lCurrentPtr; + } + ++lNbComp; + lCurrentPtr = lMatrix; + + lNbComp = (int) (sqrt(4*lNbComp + 1)/2. - 0.5); + lMctComp = lNbComp * lNbComp; + lTotalComp = lMctComp + lNbComp; + lSpace = (float *) malloc(lTotalComp * sizeof(float)); + lCurrentDoublePtr = lSpace; + for (i=0;i> */ @@ -1486,20 +1556,30 @@ void info_callback(const char *msg, void *client_data) { } /* -------------------------------------------------------------------------- */ - +/** + * IMAGE_TO_J2K MAIN + */ +/* -------------------------------------------------------------------------- */ int main(int argc, char **argv) { - opj_bool bSuccess; + FILE *f = NULL; + opj_cparameters_t parameters; /* compression parameters */ - img_fol_t img_fol; opj_event_mgr_t event_mgr; /* event manager */ + + opj_stream_t *cio = 00; + opj_codec_t* cinfo = 00; opj_image_t *image = NULL; - int i,num_images; - int imageno; - dircnt_t *dirptr = NULL; raw_cparameters_t raw_cp; opj_codestream_info_t cstr_info; /* Codestream information structure */ + char indexfilename[OPJ_PATH_LEN]; /* index file name */ + int i, num_images, imageno; + img_fol_t img_fol; + dircnt_t *dirptr = NULL; + + opj_bool bSuccess; + /* configure the event callbacks (not required) setting of each callback is optionnal @@ -1580,6 +1660,7 @@ int main(int argc, char **argv) { continue; } } + switch(parameters.decod_format) { case PGX_DFMT: break; @@ -1600,90 +1681,124 @@ int main(int argc, char **argv) { continue; } - /* decode the source image */ - /* ----------------------- */ + /* decode the source image */ + /* ----------------------- */ - switch (parameters.decod_format) { - case PGX_DFMT: - image = pgxtoimage(parameters.infile, ¶meters); - if (!image) { - fprintf(stderr, "Unable to load pgx file\n"); - return 1; - } - break; + switch (parameters.decod_format) { + case PGX_DFMT: + image = pgxtoimage(parameters.infile, ¶meters); + if (!image) { + fprintf(stderr, "Unable to load pgx file\n"); + return 1; + } + break; - case PXM_DFMT: - image = pnmtoimage(parameters.infile, ¶meters); - if (!image) { - fprintf(stderr, "Unable to load pnm file\n"); - return 1; - } - break; + case PXM_DFMT: + image = pnmtoimage(parameters.infile, ¶meters); + if (!image) { + fprintf(stderr, "Unable to load pnm file\n"); + return 1; + } + break; + + case BMP_DFMT: + image = bmptoimage(parameters.infile, ¶meters); + if (!image) { + fprintf(stderr, "Unable to load bmp file\n"); + return 1; + } + break; - case BMP_DFMT: - image = bmptoimage(parameters.infile, ¶meters); - if (!image) { - fprintf(stderr, "Unable to load bmp file\n"); - return 1; - } - break; #ifdef HAVE_LIBTIFF - case TIF_DFMT: - image = tiftoimage(parameters.infile, ¶meters); - if (!image) { - fprintf(stderr, "Unable to load tiff file\n"); - return 1; - } - break; + case TIF_DFMT: + image = tiftoimage(parameters.infile, ¶meters); + if (!image) { + fprintf(stderr, "Unable to load tiff file\n"); + return 1; + } + break; #endif /* HAVE_LIBTIFF */ - case RAW_DFMT: - image = rawtoimage(parameters.infile, ¶meters, &raw_cp); - if (!image) { - fprintf(stderr, "Unable to load raw file\n"); - return 1; - } - break; - case TGA_DFMT: - image = tgatoimage(parameters.infile, ¶meters); - if (!image) { - fprintf(stderr, "Unable to load tga file\n"); - return 1; - } - break; + case RAW_DFMT: + image = rawtoimage(parameters.infile, ¶meters, &raw_cp); + if (!image) { + fprintf(stderr, "Unable to load raw file\n"); + return 1; + } + break; + + case TGA_DFMT: + image = tgatoimage(parameters.infile, ¶meters); + if (!image) { + fprintf(stderr, "Unable to load tga file\n"); + return 1; + } + break; + #ifdef HAVE_LIBPNG - case PNG_DFMT: - image = pngtoimage(parameters.infile, ¶meters); - if (!image) { - fprintf(stderr, "Unable to load png file\n"); - return 1; - } - break; + case PNG_DFMT: + image = pngtoimage(parameters.infile, ¶meters); + if (!image) { + fprintf(stderr, "Unable to load png file\n"); + return 1; + } + break; #endif /* HAVE_LIBPNG */ } + /* Can happen if input file is TIFF or PNG * and HAVE_LIBTIF or HAVE_LIBPNG is undefined */ - if( !image) - { + if( !image) { fprintf(stderr, "Unable to load file: got no image\n"); return 1; - } - /* Decide if MCT should be used */ - parameters.tcp_mct = image->numcomps == 3 ? 1 : 0; + } - if(parameters.cp_cinema){ - cinema_setup_encoder(¶meters,image,&img_fol); + /* Decide if MCT should be used */ + parameters.tcp_mct = image->numcomps == 3 ? 1 : 0; + + if(parameters.cp_cinema){ + cinema_setup_encoder(¶meters,image,&img_fol); + } + + /* encode the destination image */ + /* ---------------------------- */ + + switch(parameters.decod_format) { + case J2K_CFMT: /* JPEG-2000 codestream */ + { + /* Get a decoder handle */ + cinfo = opj_create_compress_v2(CODEC_J2K); + break; } + case JP2_CFMT: /* JPEG 2000 compressed image data */ + { + /* Get a decoder handle */ + cinfo = opj_create_compress_v2(CODEC_JP2); + break; + } + default: + fprintf(stderr, "skipping file..\n"); + opj_stream_destroy(cio); + continue; + } - /* encode the destination image */ - /* ---------------------------- */ + opj_setup_encoder(cinfo, ¶meters, image); - if (parameters.cod_format == J2K_CFMT) { /* J2K format output */ - int codestream_length; - size_t res; - opj_cio_t *cio = NULL; - FILE *f = NULL; + /* Open the output file*/ + f = fopen(parameters.outfile, "wb"); + if (! f) { + fprintf(stderr, "Not enable to create output file!\n"); + opj_stream_destroy(cio); + return 1; + } + + + if (parameters.cod_format == J2K_CFMT) { /* J2K format output */ + int codestream_length; + size_t res; + opj_cio_t *cio = NULL; + FILE *f = NULL; /* get a J2K compressor handle */ opj_cinfo_t* cinfo = opj_create_compress(CODEC_J2K); diff --git a/libopenjpeg/j2k.c b/libopenjpeg/j2k.c index 2194e6d5..91242a0f 100644 --- a/libopenjpeg/j2k.c +++ b/libopenjpeg/j2k.c @@ -8517,3 +8517,114 @@ opj_bool j2k_set_decoded_resolution_factor(opj_j2k_v2_t *p_j2k, OPJ_UINT32 res_f return OPJ_FALSE; } + + +/** + * Encodes all the tiles in a row. + */ +opj_bool j2k_encode_v2( opj_j2k_v2_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ) +{ + OPJ_UINT32 i; + OPJ_UINT32 l_nb_tiles; + OPJ_UINT32 l_max_tile_size, l_current_tile_size; + OPJ_BYTE * l_current_data; + + /* preconditions */ + assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); + + l_current_data = (OPJ_BYTE*)opj_malloc(1000); + if (! l_current_data) { + return OPJ_FALSE; + } + l_max_tile_size = 1000; + + l_nb_tiles = p_j2k->m_cp.th * p_j2k->m_cp.tw; + for (i=0;im_tcd); + if (l_current_tile_size > l_max_tile_size) { + l_current_data = (OPJ_BYTE*)opj_realloc(l_current_data,l_current_tile_size); + if (! l_current_data) { + return OPJ_FALSE; + } + l_max_tile_size = l_current_tile_size; + } + + j2k_get_tile_data(p_j2k->m_tcd,l_current_data); + + if (! j2k_post_write_tile (p_j2k,l_current_data,l_current_tile_size,p_stream,p_manager)) { + return OPJ_FALSE; + } + } + + opj_free(l_current_data); + return OPJ_TRUE; +} + +/** + * Ends the compression procedures and possibility add data to be read after the + * codestream. + */ +opj_bool j2k_end_compress( opj_j2k_v2_t *p_j2k, + opj_stream_private_t *p_stream, + struct opj_event_mgr * p_manager) +{ + /* customization of the encoding */ + j2k_setup_end_compress(p_j2k); + + if (! j2k_exec (p_j2k, p_j2k->m_procedure_list, p_stream, p_manager)) + { + return OPJ_FALSE; + } + + return OPJ_TRUE; +} + + +/** + * Starts a compression scheme, i.e. validates the codec parameters, writes the header. + * + * @param p_j2k the jpeg2000 codec. + * @param p_stream the stream object. + * @param p_manager the user event manager. + * + * @return true if the codec is valid. + */ +opj_bool j2k_start_compress(opj_j2k_v2_t *p_j2k, + opj_stream_private_t *p_stream, + opj_image_t * p_image, + opj_event_mgr_t * p_manager) +{ + // preconditions + assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); + + p_j2k->m_image = p_image; + + /* customization of the validation */ + j2k_setup_encoding_validation (p_j2k); + + /* validation of the parameters codec */ + if (! j2k_exec(p_j2k,p_j2k->m_validation_list,p_stream,p_manager)) { + return OPJ_FALSE; + } + + /* customization of the encoding */ + j2k_setup_header_writting(p_j2k); + + /* write header */ + if (! j2k_exec (p_j2k,p_j2k->m_procedure_list,p_stream,p_manager)) { + return OPJ_FALSE; + } + + return OPJ_TRUE; +} diff --git a/libopenjpeg/j2k.h b/libopenjpeg/j2k.h index ae2f36f6..6b73cbfc 100644 --- a/libopenjpeg/j2k.h +++ b/libopenjpeg/j2k.h @@ -1024,4 +1024,20 @@ opj_bool j2k_get_tile( opj_j2k_v2_t *p_j2k, opj_bool j2k_set_decoded_resolution_factor(opj_j2k_v2_t *p_j2k, OPJ_UINT32 res_factor, opj_event_mgr_t * p_manager); +/** + * Encodes an image into a JPEG-2000 codestream + */ +opj_bool j2k_encode_v2( opj_j2k_v2_t * p_j2k, + opj_stream_private_t *cio, + struct opj_event_mgr * p_manager ); + +/** + * Ends the compression procedures and possibiliy add data to be read after the + * codestream. + */ +opj_bool j2k_end_compress( opj_j2k_v2_t *p_j2k, + opj_stream_private_t *cio, + struct opj_event_mgr * p_manager); + + #endif /* __J2K_H */ diff --git a/libopenjpeg/openjpeg.c b/libopenjpeg/openjpeg.c index 1adc126d..24496fe1 100644 --- a/libopenjpeg/openjpeg.c +++ b/libopenjpeg/openjpeg.c @@ -529,6 +529,74 @@ opj_cinfo_t* OPJ_CALLCONV opj_create_compress(OPJ_CODEC_FORMAT format) { return cinfo; } + +opj_codec_t* OPJ_CALLCONV opj_create_compress_v2(OPJ_CODEC_FORMAT p_format) +{ + opj_codec_private_t *l_info = 00; + + l_info = (opj_codec_private_t*)opj_calloc(1, sizeof(opj_codec_private_t)); + if (!l_info) { + return 00; + } + + memset(l_info, 0, sizeof(opj_codec_private_t)); + l_info->is_decompressor = 0; + + switch(p_format) { + case CODEC_J2K: + l_info->m_codec_data.m_compression.opj_encode = (opj_bool (*) ( void *, + struct opj_stream_private *, + struct opj_event_mgr * ) ) j2k_encode_v2; + + l_info->m_codec_data.m_compression.opj_end_compress = (opj_bool (*) ( void *, + struct opj_stream_private *, + struct opj_event_mgr *)) j2k_end_compress; + + l_info->m_codec_data.m_compression.opj_start_compress = (opj_bool (*) ( void *, + struct opj_stream_private *, + struct opj_image * , + struct opj_event_mgr *) ) j2k_start_compress; + + l_info->m_codec_data.m_compression.opj_write_tile = (opj_bool (*) (void *,OPJ_UINT32,OPJ_BYTE*,OPJ_UINT32,struct opj_stream_private *, struct opj_event_mgr *)) j2k_write_tile; + l_info->m_codec_data.m_compression.opj_destroy = (void (*) (void *)) j2k_destroy; + l_info->m_codec_data.m_compression.opj_setup_encoder = (void (*) (void *,opj_cparameters_t *,struct opj_image *, struct opj_event_mgr * )) j2k_setup_encoder; + + l_info->m_codec = j2k_create_compress(); + if (! l_info->m_codec) + { + opj_free(l_info); + return 00; + } + break; + + case CODEC_JP2: + /* get a JP2 decoder handle */ + l_info->m_codec_data.m_compression.opj_encode = (bool (*) (void *, struct opj_stream_private *, struct opj_event_mgr * )) opj_jp2_encode; + l_info->m_codec_data.m_compression.opj_end_compress = (bool (*) (void *, struct opj_stream_private *, struct opj_event_mgr *)) jp2_end_compress; + l_info->m_codec_data.m_compression.opj_start_compress = (bool (*) (void *,struct opj_stream_private *,struct opj_image * , struct opj_event_mgr *)) jp2_start_compress; + l_info->m_codec_data.m_compression.opj_write_tile = (bool (*) (void *,OPJ_UINT32,OPJ_BYTE*,OPJ_UINT32,struct opj_stream_private *, struct opj_event_mgr *)) jp2_write_tile; + l_info->m_codec_data.m_compression.opj_destroy = (void (*) (void *)) jp2_destroy; + l_info->m_codec_data.m_compression.opj_setup_encoder = (void (*) (void *,opj_cparameters_t *,struct opj_image *, struct opj_event_mgr * )) jp2_setup_encoder; + + l_info->m_codec = jp2_create(false); + if (! l_info->m_codec) { + opj_free(l_info); + return 00; + } + break; + + case CODEC_UNKNOWN: + case CODEC_JPT: + default: + opj_free(l_info); + return 00; + } + + set_default_event_handler(&(l_info->m_event_mgr)); + return (opj_codec_t*) l_info; +} + + void OPJ_CALLCONV opj_destroy_compress(opj_cinfo_t *cinfo) { if(cinfo) { /* destroy the codec */ @@ -1034,3 +1102,31 @@ opj_bool OPJ_CALLCONV opj_set_decoded_resolution_factor(opj_codec_t *p_codec, OP return OPJ_TRUE; } + + +opj_bool OPJ_CALLCONV opj_set_MCT(opj_cparameters_t *parameters,OPJ_FLOAT32 * pEncodingMatrix,OPJ_INT32 * p_dc_shift,OPJ_UINT32 pNbComp) +{ + OPJ_UINT32 l_matrix_size = pNbComp * pNbComp * sizeof(OPJ_FLOAT32); + OPJ_UINT32 l_dc_shift_size = pNbComp * sizeof(OPJ_INT32); + OPJ_UINT32 l_mct_total_size = l_matrix_size + l_dc_shift_size; + + /* add MCT capability */ + int rsiz = (int)parameters->cp_rsiz | (int)MCT; + parameters->cp_rsiz = (OPJ_RSIZ_CAPABILITIES)rsiz; + parameters->irreversible = 1; + + /* use array based MCT */ + parameters->tcp_mct = 2; + parameters->mct_data = opj_malloc(l_mct_total_size); + if (! parameters->mct_data) { + return OPJ_FALSE; + } + + memcpy(parameters->mct_data,pEncodingMatrix,l_matrix_size); + memcpy(((OPJ_BYTE *) parameters->mct_data) + l_matrix_size,p_dc_shift,l_dc_shift_size); + + return OPJ_TRUE; +} + + + diff --git a/libopenjpeg/openjpeg.h b/libopenjpeg/openjpeg.h index 66d45f3b..a4553f16 100644 --- a/libopenjpeg/openjpeg.h +++ b/libopenjpeg/openjpeg.h @@ -165,7 +165,8 @@ typedef OPJ_INT64 OPJ_OFF_T; typedef enum RSIZ_CAPABILITIES { STD_RSIZ = 0, /** Standard JPEG2000 profile*/ CINEMA2K = 3, /** Profile name for a 2K image*/ - CINEMA4K = 4 /** Profile name for a 4K image*/ + CINEMA4K = 4, /** Profile name for a 4K image*/ + MCT = 0x8100 } OPJ_RSIZ_CAPABILITIES; /** @@ -417,6 +418,9 @@ typedef struct opj_cparameters { char tcp_mct; /** Enable JPIP indexing*/ opj_bool jpip_on; + /** Naive implementation of MCT restricted to a single reversible array based encoding without offset concerning all the components. */ + void * mct_data; + } opj_cparameters_t; #define OPJ_DPARAMETERS_IGNORE_PCLR_CMAP_CDEF_FLAG 0x0001 @@ -1391,6 +1395,15 @@ Creates a J2K/JP2 compression structure @return Returns a handle to a compressor if successful, returns NULL otherwise */ OPJ_API opj_cinfo_t* OPJ_CALLCONV opj_create_compress(OPJ_CODEC_FORMAT format); + +/** +Creates a J2K/JP2 compression structure +@param format Coder to select +@return Returns a handle to a compressor if successful, returns NULL otherwise +*/ +OPJ_API opj_codec_t* OPJ_CALLCONV opj_create_compress_v2(OPJ_CODEC_FORMAT format); + + /** Destroy a compressor handle @param cinfo compressor handle to destroy @@ -1529,6 +1542,26 @@ OPJ_API opj_jp2_metadata_t* OPJ_CALLCONV opj_get_jp2_metadata(opj_codec_t *p_cod OPJ_API opj_jp2_index_t* OPJ_CALLCONV opj_get_jp2_index(opj_codec_t *p_codec); +/* +========================================================== + new functions +========================================================== +*/ + +/** + * Sets the MCT matrix to use. + * + * @param parameters the parameters to change. + * @param pEncodingMatrix the encoding matrix. + * @param p_dc_shift the dc shift coefficients to use. + * @param pNbComp the number of components of the image. + * + * @return true if the parameters could be set. + */ +OPJ_API opj_bool OPJ_CALLCONV opj_set_MCT( opj_cparameters_t *parameters, + OPJ_FLOAT32 * pEncodingMatrix, + OPJ_INT32 * p_dc_shift, + OPJ_UINT32 pNbComp);