X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fopenjp2%2Fj2k.c;h=c75f2b886197148d6bd6b9e015245ed1b6b53b48;hb=1fb24aba4b29b7cd1b6880d8f0b08196a12efc2c;hp=93d9999c606c6d2cead303310beecf0996763438;hpb=b7fe7d25e1fcffe3bca03b61da54a04d72cb7965;p=openjpeg.git diff --git a/src/lib/openjp2/j2k.c b/src/lib/openjp2/j2k.c index 93d9999c..c75f2b88 100644 --- a/src/lib/openjp2/j2k.c +++ b/src/lib/openjp2/j2k.c @@ -1,9 +1,15 @@ /* - * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium - * Copyright (c) 2002-2007, Professor Benoit Macq + * 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 and Antonin Descampe + * Copyright (c) 2003-2007, Francois-Olivier Devaux + * Copyright (c) 2003-2014, Antonin Descampe * Copyright (c) 2005, Herve Drolon, FreeImage Team * Copyright (c) 2008, Jerome Fimes, Communications & Systemes * Copyright (c) 2006-2007, Parvatha Elangovan @@ -36,11 +42,6 @@ #include "opj_includes.h" -#define CINEMA_24_CS 1302083 /*Codestream length for 24fps*/ -#define CINEMA_48_CS 651041 /*Codestream length for 48fps*/ -#define COMP_24_CS 1041666 /*Maximum size per color component for 2K & 4K @ 24fps*/ -#define COMP_48_CS 520833 /*Maximum size per color component for 2K @ 48fps*/ - /** @defgroup J2K J2K - JPEG-2000 codestream reader/writer */ /*@{*/ @@ -337,11 +338,21 @@ static OPJ_BOOL opj_j2k_pre_write_tile ( opj_j2k_t * p_j2k, static OPJ_BOOL opj_j2k_update_image_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data, opj_image_t* p_output_image); +static void opj_get_tile_dimensions(opj_image_t * l_image, + opj_tcd_tilecomp_t * l_tilec, + opj_image_comp_t * l_img_comp, + OPJ_UINT32* l_size_comp, + OPJ_UINT32* l_width, + OPJ_UINT32* l_height, + OPJ_UINT32* l_offset_x, + OPJ_UINT32* l_offset_y, + OPJ_UINT32* l_image_width, + OPJ_UINT32* l_stride, + OPJ_UINT32* l_tile_offset); + static void opj_j2k_get_tile_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data); static OPJ_BOOL opj_j2k_post_write_tile (opj_j2k_t * p_j2k, - OPJ_BYTE * p_data, - OPJ_UINT32 p_data_size, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager ); @@ -1166,7 +1177,7 @@ static int opj_j2k_initialise_4K_poc(opj_poc_t *POC, int numres); static void opj_j2k_set_cinema_parameters(opj_cparameters_t *parameters, opj_image_t *image, opj_event_mgr_t *p_manager); -static OPJ_BOOL opj_j2k_is_cinema_compliant(opj_image_t *image, OPJ_CINEMA_MODE cinema_mode, opj_event_mgr_t *p_manager); +static OPJ_BOOL opj_j2k_is_cinema_compliant(opj_image_t *image, OPJ_UINT16 rsiz, opj_event_mgr_t *p_manager); /*@}*/ @@ -1498,7 +1509,6 @@ OPJ_BOOL opj_j2k_check_poc_val( const opj_poc_t *p_pocs, opj_event_msg(p_manager , EVT_ERROR, "Not enough memory for checking the poc values.\n"); return OPJ_FALSE; } - memset(packet_array,0,step_l * p_num_layers* sizeof(OPJ_UINT32)); if (p_nb_pocs == 0) { opj_free(packet_array); @@ -1909,7 +1919,7 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k, OPJ_UINT32 l_nb_comp_remain; OPJ_UINT32 l_remaining_size; OPJ_UINT32 l_nb_tiles; - OPJ_UINT32 l_tmp; + OPJ_UINT32 l_tmp, l_tx1, l_ty1; opj_image_t *l_image = 00; opj_cp_t *l_cp = 00; opj_image_comp_t * l_img_comp = 00; @@ -1939,7 +1949,7 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k, opj_read_bytes(p_header_data,&l_tmp ,2); /* Rsiz (capabilities) */ p_header_data+=2; - l_cp->rsiz = (OPJ_RSIZ_CAPABILITIES) l_tmp; + l_cp->rsiz = (OPJ_UINT16) l_tmp; opj_read_bytes(p_header_data, (OPJ_UINT32*) &l_image->x1, 4); /* Xsiz */ p_header_data+=4; opj_read_bytes(p_header_data, (OPJ_UINT32*) &l_image->y1, 4); /* Ysiz */ @@ -1971,8 +1981,9 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k, } /* testcase 4035.pdf.SIGSEGV.d8b.3375 */ - if (l_image->x0 > l_image->x1 || l_image->y0 > l_image->y1) { - opj_event_msg(p_manager, EVT_ERROR, "Error with SIZ marker: negative image size (%d x %d)\n", l_image->x1 - l_image->x0, l_image->y1 - l_image->y0); + /* testcase issue427-null-image-size.jp2 */ + if ((l_image->x0 >= l_image->x1) || (l_image->y0 >= l_image->y1)) { + opj_event_msg(p_manager, EVT_ERROR, "Error with SIZ marker: negative or zero image size (%d x %d)\n", l_image->x1 - l_image->x0, l_image->y1 - l_image->y0); return OPJ_FALSE; } /* testcase 2539.pdf.SIGFPE.706.1712 (also 3622.pdf.SIGFPE.706.2916 and 4008.pdf.SIGFPE.706.3345 and maybe more) */ @@ -1983,7 +1994,21 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k, /* testcase 1610.pdf.SIGSEGV.59c.681 */ if (((OPJ_UINT64)l_image->x1) * ((OPJ_UINT64)l_image->y1) != (l_image->x1 * l_image->y1)) { - opj_event_msg(p_manager, EVT_ERROR, "Prevent buffer overflow (x1: %d, y1: %d)", l_image->x1, l_image->y1); + opj_event_msg(p_manager, EVT_ERROR, "Prevent buffer overflow (x1: %d, y1: %d)\n", l_image->x1, l_image->y1); + return OPJ_FALSE; + } + + /* testcase issue427-illegal-tile-offset.jp2 */ + l_tx1 = l_cp->tx0 + l_cp->tdx; + if (l_tx1 < l_cp->tx0) { /* manage overflow */ + l_tx1 = 0xFFFFFFFFU; + } + l_ty1 = l_cp->ty0 + l_cp->tdy; + if (l_ty1 < l_cp->ty0) { /* manage overflow */ + l_ty1 = 0xFFFFFFFFU; + } + if ((l_cp->tx0 > l_image->x0) || (l_cp->ty0 > l_image->y0) || (l_tx1 <= l_image->x0) || (l_ty1 <= l_image->y0) ) { + opj_event_msg(p_manager, EVT_ERROR, "Error with SIZ marker: illegal tile offset\n"); return OPJ_FALSE; } @@ -2037,7 +2062,6 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k, return OPJ_FALSE; } - memset(l_image->comps,0,l_image->numcomps * sizeof(opj_image_comp_t)); l_img_comp = l_image->comps; /* Read the component information */ @@ -2166,7 +2190,6 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k, opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n"); return OPJ_FALSE; } - memset(l_cp->tcps,0,l_nb_tiles*sizeof(opj_tcp_t)); #ifdef USE_JPWL if (l_cp->correct) { @@ -2187,27 +2210,24 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k, opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n"); return OPJ_FALSE; } - memset(p_j2k->m_specific_param.m_decoder.m_default_tcp->tccps ,0,l_image->numcomps*sizeof(opj_tccp_t)); p_j2k->m_specific_param.m_decoder.m_default_tcp->m_mct_records = - (opj_mct_data_t*)opj_malloc(OPJ_J2K_MCT_DEFAULT_NB_RECORDS * sizeof(opj_mct_data_t)); + (opj_mct_data_t*)opj_calloc(OPJ_J2K_MCT_DEFAULT_NB_RECORDS ,sizeof(opj_mct_data_t)); if (! p_j2k->m_specific_param.m_decoder.m_default_tcp->m_mct_records) { opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n"); return OPJ_FALSE; } - memset(p_j2k->m_specific_param.m_decoder.m_default_tcp->m_mct_records,0,OPJ_J2K_MCT_DEFAULT_NB_RECORDS * sizeof(opj_mct_data_t)); p_j2k->m_specific_param.m_decoder.m_default_tcp->m_nb_max_mct_records = OPJ_J2K_MCT_DEFAULT_NB_RECORDS; p_j2k->m_specific_param.m_decoder.m_default_tcp->m_mcc_records = (opj_simple_mcc_decorrelation_data_t*) - opj_malloc(OPJ_J2K_MCC_DEFAULT_NB_RECORDS * sizeof(opj_simple_mcc_decorrelation_data_t)); + opj_calloc(OPJ_J2K_MCC_DEFAULT_NB_RECORDS, sizeof(opj_simple_mcc_decorrelation_data_t)); if (! p_j2k->m_specific_param.m_decoder.m_default_tcp->m_mcc_records) { opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n"); return OPJ_FALSE; } - memset(p_j2k->m_specific_param.m_decoder.m_default_tcp->m_mcc_records,0,OPJ_J2K_MCC_DEFAULT_NB_RECORDS * sizeof(opj_simple_mcc_decorrelation_data_t)); p_j2k->m_specific_param.m_decoder.m_default_tcp->m_nb_max_mcc_records = OPJ_J2K_MCC_DEFAULT_NB_RECORDS; /* set up default dc level shift */ @@ -2219,12 +2239,11 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k, l_current_tile_param = l_cp->tcps; for (i = 0; i < l_nb_tiles; ++i) { - l_current_tile_param->tccps = (opj_tccp_t*) opj_malloc(l_image->numcomps * sizeof(opj_tccp_t)); + l_current_tile_param->tccps = (opj_tccp_t*) opj_calloc(l_image->numcomps, sizeof(opj_tccp_t)); if (l_current_tile_param->tccps == 00) { opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n"); return OPJ_FALSE; } - memset(l_current_tile_param->tccps,0,l_image->numcomps * sizeof(opj_tccp_t)); ++l_current_tile_param; } @@ -2421,9 +2440,19 @@ static OPJ_BOOL opj_j2k_read_cod ( opj_j2k_t *p_j2k, opj_read_bytes(p_header_data,&l_tcp->csty,1); /* Scod */ ++p_header_data; + /* Make sure we know how to decode this */ + if ((l_tcp->csty & ~(OPJ_UINT32)(J2K_CP_CSTY_PRT | J2K_CP_CSTY_SOP | J2K_CP_CSTY_EPH)) != 0U) { + opj_event_msg(p_manager, EVT_ERROR, "Unknown Scod value in COD marker\n"); + return OPJ_FALSE; + } opj_read_bytes(p_header_data,&l_tmp,1); /* SGcod (A) */ ++p_header_data; l_tcp->prg = (OPJ_PROG_ORDER) l_tmp; + /* Make sure progression order is valid */ + if (l_tcp->prg > OPJ_CPRL ) { + opj_event_msg(p_manager, EVT_ERROR, "Unknown progression order in COD marker\n"); + l_tcp->prg = OPJ_PROG_UNKNOWN; + } opj_read_bytes(p_header_data,&l_tcp->numlayers,2); /* SGcod (B) */ p_header_data+=2; @@ -3096,7 +3125,7 @@ OPJ_UINT32 opj_j2k_get_specific_header_sizes(opj_j2k_t *p_j2k) l_nb_comps = p_j2k->m_private_image->numcomps - 1; l_nb_bytes += opj_j2k_get_max_toc_size(p_j2k); - if (p_j2k->m_cp.m_specific_param.m_enc.m_cinema == 0) { + if (!(OPJ_IS_CINEMA(p_j2k->m_cp.rsiz))) { l_coc_bytes = opj_j2k_get_max_coc_size(p_j2k); l_nb_bytes += l_nb_comps * l_coc_bytes; @@ -3163,6 +3192,11 @@ static OPJ_BOOL opj_j2k_read_poc ( opj_j2k_t *p_j2k, l_old_poc_nb = l_tcp->POC ? l_tcp->numpocs + 1 : 0; l_current_poc_nb += l_old_poc_nb; + if(l_current_poc_nb >= 32) + { + opj_event_msg(p_manager, EVT_ERROR, "Too many POCs %d\n", l_current_poc_nb); + return OPJ_FALSE; + } assert(l_current_poc_nb < 32); /* now poc is in use.*/ @@ -3545,6 +3579,14 @@ OPJ_BOOL j2k_read_ppm_v3 ( /* First PPM marker */ if (l_Z_ppm == 0) { + if (l_cp->ppm_data != NULL) { + opj_event_msg(p_manager, EVT_ERROR, "Zppm O already processed. Found twice.\n"); + opj_free(l_cp->ppm_data); + l_cp->ppm_data = NULL; + l_cp->ppm_buffer = NULL; + l_cp->ppm = 0; /* do not use PPM */ + return OPJ_FALSE; + } /* We need now at least the Nppm^0 element */ if (p_header_size < 4) { opj_event_msg(p_manager, EVT_ERROR, "Error reading PPM marker\n"); @@ -3563,20 +3605,19 @@ OPJ_BOOL j2k_read_ppm_v3 ( l_cp->ppm_data = NULL; l_cp->ppm_buffer = NULL; l_cp->ppm = 0; /* do not use PPM */ - return OPJ_TRUE; + return OPJ_FALSE; } /* First PPM marker: Initialization */ l_cp->ppm_len = l_N_ppm; l_cp->ppm_data_read = 0; - l_cp->ppm_data = (OPJ_BYTE *) opj_malloc(l_cp->ppm_len); + l_cp->ppm_data = (OPJ_BYTE *) opj_calloc(1,l_cp->ppm_len); l_cp->ppm_buffer = l_cp->ppm_data; if (l_cp->ppm_data == 00) { opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read ppm marker\n"); return OPJ_FALSE; } - memset(l_cp->ppm_data,0,l_cp->ppm_len); l_cp->ppm_data_current = l_cp->ppm_data; @@ -3608,7 +3649,7 @@ OPJ_BOOL j2k_read_ppm_v3 ( l_cp->ppm_data = NULL; l_cp->ppm_buffer = NULL; l_cp->ppm = 0; /* do not use PPM */ - return OPJ_TRUE; + return OPJ_FALSE; } /* Increase the size of ppm_data to add the new Ippm series*/ assert(l_cp->ppm_data == l_cp->ppm_buffer && "We need ppm_data and ppm_buffer to be the same when reallocating"); @@ -3643,6 +3684,15 @@ OPJ_BOOL j2k_read_ppm_v3 ( if (p_header_size) { + if (p_header_size < 4) { + opj_free(l_cp->ppm_data); + l_cp->ppm_data = NULL; + l_cp->ppm_buffer = NULL; /* TODO: no need for a new local variable: ppm_buffer and ppm_data are enough */ + l_cp->ppm_len = 0; + l_cp->ppm = 0; + opj_event_msg(p_manager, EVT_ERROR, "Error reading PPM marker\n"); + return OPJ_FALSE; + } opj_read_bytes(p_header_data,&l_N_ppm,4); /* N_ppm^i */ p_header_data+=4; p_header_size-=4; @@ -3659,6 +3709,15 @@ OPJ_BOOL j2k_read_ppm_v3 ( OPJ_BYTE *new_ppm_data; /* Increase the size of ppm_data to add the new Ippm series*/ assert(l_cp->ppm_data == l_cp->ppm_buffer && "We need ppm_data and ppm_buffer to be the same when reallocating"); + /* Overflow check */ + if ((l_cp->ppm_len + l_N_ppm) < l_N_ppm) { + opj_free(l_cp->ppm_data); + l_cp->ppm_data = NULL; + l_cp->ppm_buffer = NULL; /* TODO: no need for a new local variable: ppm_buffer and ppm_data are enough */ + l_cp->ppm_len = 0; + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to increase the size of ppm_data to add the new (complete) Ippm series\n"); + return OPJ_FALSE; + } new_ppm_data = (OPJ_BYTE *) opj_realloc(l_cp->ppm_data, l_cp->ppm_len + l_N_ppm); if (! new_ppm_data) { opj_free(l_cp->ppm_data); @@ -3682,6 +3741,16 @@ OPJ_BOOL j2k_read_ppm_v3 ( if (l_remaining_data) { OPJ_BYTE *new_ppm_data; assert(l_cp->ppm_data == l_cp->ppm_buffer && "We need ppm_data and ppm_buffer to be the same when reallocating"); + + /* Overflow check */ + if ((l_cp->ppm_len + l_N_ppm) < l_N_ppm) { + opj_free(l_cp->ppm_data); + l_cp->ppm_data = NULL; + l_cp->ppm_buffer = NULL; /* TODO: no need for a new local variable: ppm_buffer and ppm_data are enough */ + l_cp->ppm_len = 0; + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to increase the size of ppm_data to add the new (complete) Ippm series\n"); + return OPJ_FALSE; + } new_ppm_data = (OPJ_BYTE *) opj_realloc(l_cp->ppm_data, l_cp->ppm_len + l_N_ppm); if (! new_ppm_data) { opj_free(l_cp->ppm_data); @@ -4122,6 +4191,10 @@ OPJ_BOOL opj_j2k_read_sot ( opj_j2k_t *p_j2k, if (!p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index) { p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index = (opj_tp_index_t*)opj_calloc(l_num_parts, sizeof(opj_tp_index_t)); + if (!p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index) { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read SOT marker. Tile index allocation failed\n"); + return OPJ_FALSE; + } } else { opj_tp_index_t *new_tp_index = (opj_tp_index_t *) opj_realloc( @@ -4129,7 +4202,7 @@ OPJ_BOOL opj_j2k_read_sot ( opj_j2k_t *p_j2k, if (! new_tp_index) { opj_free(p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index); p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index = NULL; - opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read PPT marker\n"); + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read SOT marker. Tile index allocation failed\n"); return OPJ_FALSE; } p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index = new_tp_index; @@ -4143,6 +4216,11 @@ OPJ_BOOL opj_j2k_read_sot ( opj_j2k_t *p_j2k, p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index = (opj_tp_index_t*)opj_calloc( p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].current_nb_tps, sizeof(opj_tp_index_t)); + if (!p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index) { + p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].current_nb_tps = 0; + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read SOT marker. Tile index allocation failed\n"); + return OPJ_FALSE; + } } if ( l_current_part >= p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].current_nb_tps ){ @@ -4155,7 +4233,7 @@ OPJ_BOOL opj_j2k_read_sot ( opj_j2k_t *p_j2k, opj_free(p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index); p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index = NULL; p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].current_nb_tps = 0; - opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read PPT marker\n"); + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read SOT marker. Tile index allocation failed\n"); return OPJ_FALSE; } p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index = new_tp_index; @@ -4310,6 +4388,12 @@ OPJ_BOOL opj_j2k_read_sod (opj_j2k_t *p_j2k, /* Patch to support new PHR data */ if (p_j2k->m_specific_param.m_decoder.m_sot_length) { + /* If we are here, we'll try to read the data after allocation */ + /* Check enough bytes left in stream before allocation */ + if ((OPJ_OFF_T)p_j2k->m_specific_param.m_decoder.m_sot_length > opj_stream_get_number_byte_left(p_stream)) { + 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 consistant, we could simplify the code to only use realloc(), as realloc(0,...) default to malloc(0,...). @@ -4711,7 +4795,7 @@ OPJ_BOOL opj_j2k_update_rates( opj_j2k_t *p_j2k, return OPJ_FALSE; } - if (l_cp->m_specific_param.m_enc.m_cinema) { + if (OPJ_IS_CINEMA(l_cp->rsiz)) { p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer = (OPJ_BYTE *) opj_malloc(5*p_j2k->m_specific_param.m_encoder.m_total_tile_parts); if (! p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer) { @@ -5152,6 +5236,7 @@ static OPJ_BOOL opj_j2k_read_mct ( opj_j2k_t *p_j2k, } l_mct_data = l_tcp->m_mct_records + l_tcp->m_nb_mct_records; + ++l_tcp->m_nb_mct_records; } if (l_mct_data->m_data) { @@ -5180,7 +5265,6 @@ static OPJ_BOOL opj_j2k_read_mct ( opj_j2k_t *p_j2k, memcpy(l_mct_data->m_data,p_header_data,p_header_size); l_mct_data->m_data_size = p_header_size; - ++l_tcp->m_nb_mct_records; return OPJ_TRUE; } @@ -5847,12 +5931,11 @@ void opj_j2k_setup_decoder(opj_j2k_t *j2k, opj_dparameters_t *parameters) opj_j2k_t* opj_j2k_create_compress(void) { - opj_j2k_t *l_j2k = (opj_j2k_t*) opj_malloc(sizeof(opj_j2k_t)); + opj_j2k_t *l_j2k = (opj_j2k_t*) opj_calloc(1,sizeof(opj_j2k_t)); if (!l_j2k) { return NULL; } - memset(l_j2k,0,sizeof(opj_j2k_t)); l_j2k->m_is_decoder = 0; l_j2k->m_cp.m_is_decoder = 0; @@ -5903,24 +5986,8 @@ int opj_j2k_initialise_4K_poc(opj_poc_t *POC, int numres){ void opj_j2k_set_cinema_parameters(opj_cparameters_t *parameters, opj_image_t *image, opj_event_mgr_t *p_manager) { /* Configure cinema parameters */ - OPJ_FLOAT32 max_rate = 0; - OPJ_FLOAT32 temp_rate = 0; int i; - /* profile (Rsiz) */ - switch (parameters->cp_cinema){ - case OPJ_CINEMA2K_24: - case OPJ_CINEMA2K_48: - parameters->cp_rsiz = OPJ_CINEMA2K; - break; - case OPJ_CINEMA4K_24: - parameters->cp_rsiz = OPJ_CINEMA4K; - break; - case OPJ_OFF: - assert(0); - break; - } - /* No tiling */ parameters->tile_size_on = OPJ_FALSE; parameters->cp_tdx=1; @@ -5958,15 +6025,16 @@ void opj_j2k_set_cinema_parameters(opj_cparameters_t *parameters, opj_image_t *i opj_event_msg(p_manager, EVT_WARNING, "JPEG 2000 Profile-3 and 4 (2k/4k dc profile) requires:\n" "1 single quality layer" - "-> Number of layers forced to 1 (rather than %d)\n", - parameters->tcp_numlayers); + "-> Number of layers forced to 1 (rather than %d)\n" + "-> Rate of the last layer (%3.1f) will be used", + parameters->tcp_numlayers, parameters->tcp_rates[parameters->tcp_numlayers-1]); + parameters->tcp_rates[0] = parameters->tcp_rates[parameters->tcp_numlayers-1]; parameters->tcp_numlayers = 1; } /* Resolution levels */ - switch (parameters->cp_cinema){ - case OPJ_CINEMA2K_24: - case OPJ_CINEMA2K_48: + switch (parameters->rsiz){ + case OPJ_PROFILE_CINEMA_2K: if(parameters->numresolution > 6){ opj_event_msg(p_manager, EVT_WARNING, "JPEG 2000 Profile-3 (2k dc profile) requires:\n" @@ -5976,7 +6044,7 @@ void opj_j2k_set_cinema_parameters(opj_cparameters_t *parameters, opj_image_t *i parameters->numresolution = 6; } break; - case OPJ_CINEMA4K_24: + case OPJ_PROFILE_CINEMA_4K: if(parameters->numresolution < 2){ opj_event_msg(p_manager, EVT_WARNING, "JPEG 2000 Profile-4 (4k dc profile) requires:\n" @@ -6009,7 +6077,7 @@ void opj_j2k_set_cinema_parameters(opj_cparameters_t *parameters, opj_image_t *i parameters->prog_order = OPJ_CPRL; /* Progression order changes for 4K, disallowed for 2K */ - if (parameters->cp_cinema == OPJ_CINEMA4K_24) { + if (parameters->rsiz == OPJ_PROFILE_CINEMA_4K) { parameters->numpocs = (OPJ_UINT32)opj_j2k_initialise_4K_poc(parameters->POC,parameters->numresolution); } else { parameters->numpocs = 0; @@ -6017,62 +6085,42 @@ void opj_j2k_set_cinema_parameters(opj_cparameters_t *parameters, opj_image_t *i /* Limited bit-rate */ parameters->cp_disto_alloc = 1; - switch (parameters->cp_cinema){ - case OPJ_CINEMA2K_24: - case OPJ_CINEMA4K_24: - max_rate = (OPJ_FLOAT32) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec)/ - (OPJ_FLOAT32)(CINEMA_24_CS * 8 * image->comps[0].dx * image->comps[0].dy); - if (parameters->tcp_rates[0] == 0){ - parameters->tcp_rates[0] = max_rate; - }else{ - temp_rate =(OPJ_FLOAT32)(image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec)/ - (parameters->tcp_rates[0] * 8 * (OPJ_FLOAT32)image->comps[0].dx * (OPJ_FLOAT32)image->comps[0].dy); - if (temp_rate > CINEMA_24_CS ){ - opj_event_msg(p_manager, EVT_WARNING, - "JPEG 2000 Profile-3 and 4 (2k/4k dc profile) requires:\n" - "Maximum 1302083 compressed bytes @ 24fps\n" - "-> Specified rate (%3.1f) exceeds this limit. Rate will be forced to %3.1f.\n", - parameters->tcp_rates[0], max_rate); - parameters->tcp_rates[0]= max_rate; - }else{ - opj_event_msg(p_manager, EVT_WARNING, - "JPEG 2000 Profile-3 and 4 (2k/4k dc profile):\n" - "INFO : Specified rate (%3.1f) is below the 2k/4k limit @ 24fps.\n", - parameters->tcp_rates[0]); - } - } - parameters->max_comp_size = COMP_24_CS; - break; - case OPJ_CINEMA2K_48: - max_rate = ((float) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec))/ - (float)(CINEMA_48_CS * 8 * image->comps[0].dx * image->comps[0].dy); - if (parameters->tcp_rates[0] == 0){ - parameters->tcp_rates[0] = max_rate; - }else{ - temp_rate =((float) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec))/ - (parameters->tcp_rates[0] * 8 * (float)image->comps[0].dx * (float)image->comps[0].dy); - if (temp_rate > CINEMA_48_CS ){ - opj_event_msg(p_manager, EVT_WARNING, - "JPEG 2000 Profile-3 (2k dc profile) requires:\n" - "Maximum 651041 compressed bytes @ 48fps\n" - "-> Specified rate (%3.1f) exceeds this limit. Rate will be forced to %3.1f.\n", - parameters->tcp_rates[0], max_rate); - parameters->tcp_rates[0]= max_rate; - }else{ - opj_event_msg(p_manager, EVT_WARNING, - "JPEG 2000 Profile-3 (2k dc profile):\n" - "INFO : Specified rate (%3.1f) is below the 2k limit @ 48 fps.\n", - parameters->tcp_rates[0]); - } - } - parameters->max_comp_size = COMP_48_CS; - break; - default: - break; + if (parameters->max_cs_size <= 0) { + /* No rate has been introduced, 24 fps is assumed */ + parameters->max_cs_size = OPJ_CINEMA_24_CS; + opj_event_msg(p_manager, EVT_WARNING, + "JPEG 2000 Profile-3 and 4 (2k/4k dc profile) requires:\n" + "Maximum 1302083 compressed bytes @ 24fps\n" + "As no rate has been given, this limit will be used.\n"); + } else if (parameters->max_cs_size > OPJ_CINEMA_24_CS) { + opj_event_msg(p_manager, EVT_WARNING, + "JPEG 2000 Profile-3 and 4 (2k/4k dc profile) requires:\n" + "Maximum 1302083 compressed bytes @ 24fps\n" + "-> Specified rate exceeds this limit. Rate will be forced to 1302083 bytes.\n"); + parameters->max_cs_size = OPJ_CINEMA_24_CS; } + + if (parameters->max_comp_size <= 0) { + /* No rate has been introduced, 24 fps is assumed */ + parameters->max_comp_size = OPJ_CINEMA_24_COMP; + opj_event_msg(p_manager, EVT_WARNING, + "JPEG 2000 Profile-3 and 4 (2k/4k dc profile) requires:\n" + "Maximum 1041666 compressed bytes @ 24fps\n" + "As no rate has been given, this limit will be used.\n"); + } else if (parameters->max_comp_size > OPJ_CINEMA_24_COMP) { + opj_event_msg(p_manager, EVT_WARNING, + "JPEG 2000 Profile-3 and 4 (2k/4k dc profile) requires:\n" + "Maximum 1041666 compressed bytes @ 24fps\n" + "-> Specified rate exceeds this limit. Rate will be forced to 1041666 bytes.\n"); + parameters->max_comp_size = OPJ_CINEMA_24_COMP; + } + + parameters->tcp_rates[0] = (OPJ_FLOAT32) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec)/ + (OPJ_FLOAT32)(((OPJ_UINT32)parameters->max_cs_size) * 8 * image->comps[0].dx * image->comps[0].dy); + } -OPJ_BOOL opj_j2k_is_cinema_compliant(opj_image_t *image, OPJ_CINEMA_MODE cinema_mode, opj_event_mgr_t *p_manager) +OPJ_BOOL opj_j2k_is_cinema_compliant(opj_image_t *image, OPJ_UINT16 rsiz, opj_event_mgr_t *p_manager) { OPJ_UINT32 i; @@ -6104,9 +6152,8 @@ OPJ_BOOL opj_j2k_is_cinema_compliant(opj_image_t *image, OPJ_CINEMA_MODE cinema_ } /* Image size */ - switch (cinema_mode){ - case OPJ_CINEMA2K_24: - case OPJ_CINEMA2K_48: + switch (rsiz){ + case OPJ_PROFILE_CINEMA_2K: if (((image->comps[0].w > 2048) | (image->comps[0].h > 1080))){ opj_event_msg(p_manager, EVT_WARNING, "JPEG 2000 Profile-3 (2k dc profile) requires:\n" @@ -6117,7 +6164,7 @@ OPJ_BOOL opj_j2k_is_cinema_compliant(opj_image_t *image, OPJ_CINEMA_MODE cinema_ return OPJ_FALSE; } break; - case OPJ_CINEMA4K_24: + case OPJ_PROFILE_CINEMA_4K: if (((image->comps[0].w > 4096) | (image->comps[0].h > 2160))){ opj_event_msg(p_manager, EVT_WARNING, "JPEG 2000 Profile-4 (4k dc profile) requires:\n" @@ -6135,7 +6182,7 @@ OPJ_BOOL opj_j2k_is_cinema_compliant(opj_image_t *image, OPJ_CINEMA_MODE cinema_ return OPJ_TRUE; } -void opj_j2k_setup_encoder( opj_j2k_t *p_j2k, +OPJ_BOOL opj_j2k_setup_encoder( opj_j2k_t *p_j2k, opj_cparameters_t *parameters, opj_image_t *image, opj_event_mgr_t * p_manager) @@ -6144,7 +6191,12 @@ void opj_j2k_setup_encoder( opj_j2k_t *p_j2k, opj_cp_t *cp = 00; if(!p_j2k || !parameters || ! image) { - return; + return OPJ_FALSE; + } + + if ((parameters->numresolution <= 0) || (parameters->numresolution > OPJ_J2K_MAXRLVLS)) { + opj_event_msg(p_manager, EVT_ERROR, "Invalid number of resolutions : %d not in range [1,%d]\n", parameters->numresolution, OPJ_J2K_MAXRLVLS); + return OPJ_FALSE; } /* keep a link to cp so that we can destroy it later in j2k_destroy_compress */ @@ -6154,20 +6206,130 @@ void opj_j2k_setup_encoder( opj_j2k_t *p_j2k, cp->tw = 1; cp->th = 1; + /* FIXME ADE: to be removed once deprecated cp_cinema and cp_rsiz have been removed */ + if (parameters->rsiz == OPJ_PROFILE_NONE) { /* consider deprecated fields only if RSIZ has not been set */ + OPJ_BOOL deprecated_used = OPJ_FALSE; + switch (parameters->cp_cinema){ + case OPJ_CINEMA2K_24: + parameters->rsiz = OPJ_PROFILE_CINEMA_2K; + parameters->max_cs_size = OPJ_CINEMA_24_CS; + parameters->max_comp_size = OPJ_CINEMA_24_COMP; + deprecated_used = OPJ_TRUE; + break; + case OPJ_CINEMA2K_48: + parameters->rsiz = OPJ_PROFILE_CINEMA_2K; + parameters->max_cs_size = OPJ_CINEMA_48_CS; + parameters->max_comp_size = OPJ_CINEMA_48_COMP; + deprecated_used = OPJ_TRUE; + break; + case OPJ_CINEMA4K_24: + parameters->rsiz = OPJ_PROFILE_CINEMA_4K; + parameters->max_cs_size = OPJ_CINEMA_24_CS; + parameters->max_comp_size = OPJ_CINEMA_24_COMP; + deprecated_used = OPJ_TRUE; + break; + case OPJ_OFF: + default: + break; + } + switch (parameters->cp_rsiz){ + case OPJ_CINEMA2K: + parameters->rsiz = OPJ_PROFILE_CINEMA_2K; + deprecated_used = OPJ_TRUE; + break; + case OPJ_CINEMA4K: + parameters->rsiz = OPJ_PROFILE_CINEMA_4K; + deprecated_used = OPJ_TRUE; + break; + case OPJ_MCT: + parameters->rsiz = OPJ_PROFILE_PART2 | OPJ_EXTENSION_MCT; + deprecated_used = OPJ_TRUE; + case OPJ_STD_RSIZ: + default: + break; + } + if (deprecated_used) { + opj_event_msg(p_manager, EVT_WARNING, + "Deprecated fields cp_cinema or cp_rsiz are used\n" + "Please consider using only the rsiz field\n" + "See openjpeg.h documentation for more details\n"); + } + } + + /* see if max_codestream_size does limit input rate */ + if (parameters->max_cs_size <= 0) { + if (parameters->tcp_rates[parameters->tcp_numlayers-1] > 0) { + OPJ_FLOAT32 temp_size; + temp_size =(OPJ_FLOAT32)(image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec)/ + (parameters->tcp_rates[parameters->tcp_numlayers-1] * 8 * (OPJ_FLOAT32)image->comps[0].dx * (OPJ_FLOAT32)image->comps[0].dy); + parameters->max_cs_size = (int) floor(temp_size); + } else { + parameters->max_cs_size = 0; + } + } else { + OPJ_FLOAT32 temp_rate; + OPJ_BOOL cap = OPJ_FALSE; + temp_rate = (OPJ_FLOAT32) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec)/ + (OPJ_FLOAT32)(((OPJ_UINT32)parameters->max_cs_size) * 8 * image->comps[0].dx * image->comps[0].dy); + for (i = 0; i < (OPJ_UINT32) parameters->tcp_numlayers; i++) { + if (parameters->tcp_rates[i] < temp_rate) { + parameters->tcp_rates[i] = temp_rate; + cap = OPJ_TRUE; + } + } + if (cap) { + opj_event_msg(p_manager, EVT_WARNING, + "The desired maximum codestream size has limited\n" + "at least one of the desired quality layers\n"); + } + } + + /* Manage profiles and applications and set RSIZ */ /* set cinema parameters if required */ - if (parameters->cp_cinema){ - opj_j2k_set_cinema_parameters(parameters,image,p_manager); - if (!opj_j2k_is_cinema_compliant(image,parameters->cp_cinema,p_manager)) { - parameters->cp_rsiz = OPJ_STD_RSIZ; + if (OPJ_IS_CINEMA(parameters->rsiz)){ + if ((parameters->rsiz == OPJ_PROFILE_CINEMA_S2K) + || (parameters->rsiz == OPJ_PROFILE_CINEMA_S4K)){ + opj_event_msg(p_manager, EVT_WARNING, + "JPEG 2000 Scalable Digital Cinema profiles not yet supported\n"); + parameters->rsiz = OPJ_PROFILE_NONE; + } else { + opj_j2k_set_cinema_parameters(parameters,image,p_manager); + if (!opj_j2k_is_cinema_compliant(image,parameters->rsiz,p_manager)) { + parameters->rsiz = OPJ_PROFILE_NONE; + } + } + } else if (OPJ_IS_STORAGE(parameters->rsiz)) { + opj_event_msg(p_manager, EVT_WARNING, + "JPEG 2000 Long Term Storage profile not yet supported\n"); + parameters->rsiz = OPJ_PROFILE_NONE; + } else if (OPJ_IS_BROADCAST(parameters->rsiz)) { + opj_event_msg(p_manager, EVT_WARNING, + "JPEG 2000 Broadcast profiles not yet supported\n"); + parameters->rsiz = OPJ_PROFILE_NONE; + } else if (OPJ_IS_IMF(parameters->rsiz)) { + opj_event_msg(p_manager, EVT_WARNING, + "JPEG 2000 IMF profiles not yet supported\n"); + parameters->rsiz = OPJ_PROFILE_NONE; + } else if (OPJ_IS_PART2(parameters->rsiz)) { + if (parameters->rsiz == ((OPJ_PROFILE_PART2) | (OPJ_EXTENSION_NONE))) { + opj_event_msg(p_manager, EVT_WARNING, + "JPEG 2000 Part-2 profile defined\n" + "but no Part-2 extension enabled.\n" + "Profile set to NONE.\n"); + parameters->rsiz = OPJ_PROFILE_NONE; + } else if (parameters->rsiz != ((OPJ_PROFILE_PART2) | (OPJ_EXTENSION_MCT))) { + opj_event_msg(p_manager, EVT_WARNING, + "Unsupported Part-2 extension enabled\n" + "Profile set to NONE.\n"); + parameters->rsiz = OPJ_PROFILE_NONE; } } /* copy user encoding parameters */ - cp->m_specific_param.m_enc.m_cinema = parameters->cp_cinema; cp->m_specific_param.m_enc.m_max_comp_size = (OPJ_UINT32)parameters->max_comp_size; - cp->rsiz = parameters->cp_rsiz; + cp->rsiz = parameters->rsiz; cp->m_specific_param.m_enc.m_disto_alloc = (OPJ_UINT32)parameters->cp_disto_alloc & 1u; cp->m_specific_param.m_enc.m_fixed_alloc = (OPJ_UINT32)parameters->cp_fixed_alloc & 1u; cp->m_specific_param.m_enc.m_fixed_quality = (OPJ_UINT32)parameters->cp_fixed_quality & 1u; @@ -6176,6 +6338,10 @@ void opj_j2k_setup_encoder( opj_j2k_t *p_j2k, if (parameters->cp_fixed_alloc && parameters->cp_matrice) { size_t array_size = (size_t)parameters->tcp_numlayers * (size_t)parameters->numresolution * 3 * sizeof(OPJ_INT32); cp->m_specific_param.m_enc.m_matrice = (OPJ_INT32 *) opj_malloc(array_size); + if (!cp->m_specific_param.m_enc.m_matrice) { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to allocate copy of user encoding parameters matrix \n"); + return OPJ_FALSE; + } memcpy(cp->m_specific_param.m_enc.m_matrice, parameters->cp_matrice, array_size); } @@ -6189,11 +6355,36 @@ void opj_j2k_setup_encoder( opj_j2k_t *p_j2k, /* comment string */ if(parameters->cp_comment) { - cp->comment = (char*)opj_malloc(strlen(parameters->cp_comment) + 1); - if(cp->comment) { - strcpy(cp->comment, parameters->cp_comment); - } - } + cp->comment = (char*)opj_malloc(strlen(parameters->cp_comment) + 1U); + if(!cp->comment) { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to allocate copy of comment string\n"); + return OPJ_FALSE; + } + strcpy(cp->comment, parameters->cp_comment); + } else { + /* Create default comment for codestream */ + const char comment[] = "Created by OpenJPEG version "; + const size_t clen = strlen(comment); + const char *version = opj_version(); + + /* UniPG>> */ +#ifdef USE_JPWL + cp->comment = (char*)opj_malloc(clen+strlen(version)+11); + if(!cp->comment) { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to allocate comment string\n"); + return OPJ_FALSE; + } + sprintf(cp->comment,"%s%s with JPWL", comment, version); +#else + cp->comment = (char*)opj_malloc(clen+strlen(version)+1); + if(!cp->comment) { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to allocate comment string\n"); + return OPJ_FALSE; + } + sprintf(cp->comment,"%s%s", comment, version); +#endif + /* <tcps = (opj_tcp_t*) opj_calloc(cp->tw * cp->th, sizeof(opj_tcp_t)); + if (!cp->tcps) { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to allocate tile coding parameters\n"); + return OPJ_FALSE; + } if (parameters->numpocs) { /* initialisation of POC */ opj_j2k_check_poc_val(parameters->POC,parameters->numpocs, (OPJ_UINT32)parameters->numresolution, image->numcomps, (OPJ_UINT32)parameters->tcp_numlayers, p_manager); @@ -6282,7 +6477,7 @@ void opj_j2k_setup_encoder( opj_j2k_t *p_j2k, tcp->numlayers = (OPJ_UINT32)parameters->tcp_numlayers; for (j = 0; j < tcp->numlayers; j++) { - if(cp->m_specific_param.m_enc.m_cinema){ + if(OPJ_IS_CINEMA(cp->rsiz)){ if (cp->m_specific_param.m_enc.m_fixed_quality) { tcp->distoratio[j] = parameters->tcp_distoratio[j]; } @@ -6328,24 +6523,54 @@ void opj_j2k_setup_encoder( opj_j2k_t *p_j2k, } tcp->tccps = (opj_tccp_t*) opj_calloc(image->numcomps, sizeof(opj_tccp_t)); - + if (!tcp->tccps) { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to allocate tile component coding parameters\n"); + return OPJ_FALSE; + } if (parameters->mct_data) { OPJ_UINT32 lMctSize = image->numcomps * image->numcomps * (OPJ_UINT32)sizeof(OPJ_FLOAT32); OPJ_FLOAT32 * lTmpBuf = (OPJ_FLOAT32*)opj_malloc(lMctSize); OPJ_INT32 * l_dc_shift = (OPJ_INT32 *) ((OPJ_BYTE *) parameters->mct_data + lMctSize); + if (!lTmpBuf) { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to allocate temp buffer\n"); + return OPJ_FALSE; + } + tcp->mct = 2; tcp->m_mct_coding_matrix = (OPJ_FLOAT32*)opj_malloc(lMctSize); + if (! tcp->m_mct_coding_matrix) { + opj_free(lTmpBuf); + lTmpBuf = NULL; + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to allocate encoder MCT coding matrix \n"); + return OPJ_FALSE; + } memcpy(tcp->m_mct_coding_matrix,parameters->mct_data,lMctSize); memcpy(lTmpBuf,parameters->mct_data,lMctSize); tcp->m_mct_decoding_matrix = (OPJ_FLOAT32*)opj_malloc(lMctSize); - assert(opj_matrix_inversion_f(lTmpBuf,(tcp->m_mct_decoding_matrix),image->numcomps)); + if (! tcp->m_mct_decoding_matrix) { + opj_free(lTmpBuf); + lTmpBuf = NULL; + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to allocate encoder MCT decoding matrix \n"); + return OPJ_FALSE; + } + if(opj_matrix_inversion_f(lTmpBuf,(tcp->m_mct_decoding_matrix),image->numcomps) == OPJ_FALSE) { + opj_free(lTmpBuf); + lTmpBuf = NULL; + opj_event_msg(p_manager, EVT_ERROR, "Failed to inverse encoder MCT decoding matrix \n"); + return OPJ_FALSE; + } tcp->mct_norms = (OPJ_FLOAT64*) opj_malloc(image->numcomps * sizeof(OPJ_FLOAT64)); - + if (! tcp->mct_norms) { + opj_free(lTmpBuf); + lTmpBuf = NULL; + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to allocate encoder MCT norms \n"); + return OPJ_FALSE; + } opj_calculate_norms(tcp->mct_norms,image->numcomps,tcp->m_mct_decoding_matrix); opj_free(lTmpBuf); @@ -6354,9 +6579,22 @@ void opj_j2k_setup_encoder( opj_j2k_t *p_j2k, tccp->m_dc_level_shift = l_dc_shift[i]; } - opj_j2k_setup_mct_encoding(tcp,image); + if (opj_j2k_setup_mct_encoding(tcp,image) == OPJ_FALSE) { + /* free will be handled by opj_j2k_destroy */ + opj_event_msg(p_manager, EVT_ERROR, "Failed to setup j2k mct encoding\n"); + return OPJ_FALSE; + } } else { + if(tcp->mct==1 && image->numcomps >= 3) { /* RGB->YCC MCT is enabled */ + if ((image->comps[0].dx != image->comps[1].dx) || + (image->comps[0].dx != image->comps[2].dx) || + (image->comps[0].dy != image->comps[1].dy) || + (image->comps[0].dy != image->comps[2].dy)) { + opj_event_msg(p_manager, EVT_WARNING, "Cannot perform MCT on components with different sizes. Disabling MCT.\n"); + tcp->mct = 0; + } + } for (i = 0; i < image->numcomps; i++) { opj_tccp_t *tccp = &tcp->tccps[i]; opj_image_comp_t * l_comp = &(image->comps[i]); @@ -6443,6 +6681,7 @@ void opj_j2k_setup_encoder( opj_j2k_t *p_j2k, opj_free(parameters->mct_data); parameters->mct_data = 00; } + return OPJ_TRUE; } static OPJ_BOOL opj_j2k_add_mhmarker(opj_codestream_index_t *cstr_index, OPJ_UINT32 type, OPJ_OFF_T pos, OPJ_UINT32 len) @@ -6835,12 +7074,20 @@ OPJ_BOOL opj_j2k_encoding_validation ( opj_j2k_t * p_j2k, /* make sure a validation list is present */ l_is_valid &= (p_j2k->m_validation_list != 00); - if ((p_j2k->m_cp.tdx) < (OPJ_UINT32) (1 << p_j2k->m_cp.tcps->tccps->numresolutions)) { + /* ISO 15444-1:2004 states between 1 & 33 (0 -> 32) */ + /* 33 (32) would always fail the check below (if a cast to 64bits was done) */ + /* FIXME Shall we change OPJ_J2K_MAXRLVLS to 32 ? */ + if ((p_j2k->m_cp.tcps->tccps->numresolutions <= 0) || (p_j2k->m_cp.tcps->tccps->numresolutions > 32)) { + opj_event_msg(p_manager, EVT_ERROR, "Number of resolutions is too high in comparison to the size of tiles\n"); + return OPJ_FALSE; + } + + if ((p_j2k->m_cp.tdx) < (OPJ_UINT32) (1 << (p_j2k->m_cp.tcps->tccps->numresolutions - 1U))) { opj_event_msg(p_manager, EVT_ERROR, "Number of resolutions is too high in comparison to the size of tiles\n"); return OPJ_FALSE; } - if ((p_j2k->m_cp.tdy) < (OPJ_UINT32) (1 << p_j2k->m_cp.tcps->tccps->numresolutions)) { + if ((p_j2k->m_cp.tdy) < (OPJ_UINT32) (1 << (p_j2k->m_cp.tcps->tccps->numresolutions - 1U))) { opj_event_msg(p_manager, EVT_ERROR, "Number of resolutions is too high in comparison to the size of tiles\n"); return OPJ_FALSE; } @@ -6886,6 +7133,9 @@ OPJ_BOOL opj_j2k_read_header_procedure( opj_j2k_t *p_j2k, OPJ_UINT32 l_current_marker; OPJ_UINT32 l_marker_size; const opj_dec_memory_marker_handler_t * l_marker_handler = 00; + OPJ_BOOL l_has_siz = 0; + OPJ_BOOL l_has_cod = 0; + OPJ_BOOL l_has_qcd = 0; /* preconditions */ assert(p_stream != 00); @@ -6915,7 +7165,7 @@ OPJ_BOOL opj_j2k_read_header_procedure( opj_j2k_t *p_j2k, /* Check if the current marker ID is valid */ if (l_current_marker < 0xff00) { - opj_event_msg(p_manager, EVT_ERROR, "We expected read a marker ID (0xff--) instead of %.8x\n", l_current_marker); + opj_event_msg(p_manager, EVT_ERROR, "A marker ID was expected (0xff--) instead of %.8x\n", l_current_marker); return OPJ_FALSE; } @@ -6935,6 +7185,19 @@ OPJ_BOOL opj_j2k_read_header_procedure( opj_j2k_t *p_j2k, l_marker_handler = opj_j2k_get_marker_handler(l_current_marker); } + if (l_marker_handler->id == J2K_MS_SIZ) { + /* Mark required SIZ marker as found */ + l_has_siz = 1; + } + if (l_marker_handler->id == J2K_MS_COD) { + /* Mark required COD marker as found */ + l_has_cod = 1; + } + if (l_marker_handler->id == J2K_MS_QCD) { + /* Mark required QCD marker as found */ + l_has_qcd = 1; + } + /* Check if the marker is known and if it is the right place to find it */ if (! (p_j2k->m_specific_param.m_decoder.m_state & l_marker_handler->states) ) { opj_event_msg(p_manager, EVT_ERROR, "Marker is not compliant with its position\n"); @@ -6997,6 +7260,19 @@ OPJ_BOOL opj_j2k_read_header_procedure( opj_j2k_t *p_j2k, opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data,&l_current_marker,2); } + if (l_has_siz == 0) { + opj_event_msg(p_manager, EVT_ERROR, "required SIZ marker not found in main header\n"); + return OPJ_FALSE; + } + if (l_has_cod == 0) { + opj_event_msg(p_manager, EVT_ERROR, "required COD marker not found in main header\n"); + return OPJ_FALSE; + } + if (l_has_qcd == 0) { + opj_event_msg(p_manager, EVT_ERROR, "required QCD marker not found in main header\n"); + return OPJ_FALSE; + } + opj_event_msg(p_manager, EVT_INFO, "Main header has been correctly decoded.\n"); /* Position of the last element if the main header */ @@ -7433,6 +7709,12 @@ OPJ_BOOL opj_j2k_read_tile_header( opj_j2k_t * p_j2k, /* Read 2 bytes from the buffer as the marker size */ opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data,&l_marker_size,2); + /* Check marker size (does not include marker ID but includes marker size) */ + if (l_marker_size < 2) { + opj_event_msg(p_manager, EVT_ERROR, "Inconsistent marker size\n"); + return OPJ_FALSE; + } + /* cf. https://code.google.com/p/openjpeg/issues/detail?id=226 */ if (l_current_marker == 0x8080 && opj_stream_get_number_byte_left(p_stream) == 0) { p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_NEOC; @@ -7457,7 +7739,14 @@ OPJ_BOOL opj_j2k_read_tile_header( opj_j2k_t * p_j2k, /* Check if the marker size is compatible with the header data size */ if (l_marker_size > p_j2k->m_specific_param.m_decoder.m_header_data_size) { - OPJ_BYTE *new_header_data = (OPJ_BYTE *) opj_realloc(p_j2k->m_specific_param.m_decoder.m_header_data, l_marker_size); + OPJ_BYTE *new_header_data = NULL; + /* If we are here, this means we consider this marker as known & we will read it */ + /* Check enough bytes left in stream before allocation */ + if ((OPJ_OFF_T)l_marker_size > opj_stream_get_number_byte_left(p_stream)) { + opj_event_msg(p_manager, EVT_ERROR, "Marker size inconsistent with stream length\n"); + return OPJ_FALSE; + } + new_header_data = (OPJ_BYTE *) opj_realloc(p_j2k->m_specific_param.m_decoder.m_header_data, l_marker_size); if (! new_header_data) { opj_free(p_j2k->m_specific_param.m_decoder.m_header_data); p_j2k->m_specific_param.m_decoder.m_header_data = NULL; @@ -7593,7 +7882,7 @@ OPJ_BOOL opj_j2k_read_tile_header( opj_j2k_t * p_j2k, } opj_event_msg(p_manager, EVT_INFO, "Header of tile %d / %d has been read.\n", - p_j2k->m_current_tile_number, (p_j2k->m_cp.th * p_j2k->m_cp.tw) - 1); + p_j2k->m_current_tile_number+1, (p_j2k->m_cp.th * p_j2k->m_cp.tw)); *p_tile_index = p_j2k->m_current_tile_number; *p_go_on = OPJ_TRUE; @@ -7678,13 +7967,13 @@ OPJ_BOOL opj_j2k_decode_tile ( opj_j2k_t * p_j2k, p_j2k->m_specific_param.m_decoder.m_state = 0x0100;/*FIXME J2K_DEC_STATE_EOC;*/ } else if (l_current_marker != J2K_MS_SOT) - { - opj_event_msg(p_manager, EVT_ERROR, "Stream too short, expected SOT\n"); - + { if(opj_stream_get_number_byte_left(p_stream) == 0) { p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_NEOC; + opj_event_msg(p_manager, EVT_WARNING, "Stream does not end with EOC\n"); return OPJ_TRUE; } + opj_event_msg(p_manager, EVT_ERROR, "Stream too short, expected SOT\n"); return OPJ_FALSE; } } @@ -7698,10 +7987,10 @@ OPJ_BOOL opj_j2k_update_image_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data, opj_im OPJ_UINT32 l_width_src,l_height_src; OPJ_UINT32 l_width_dest,l_height_dest; OPJ_INT32 l_offset_x0_src, l_offset_y0_src, l_offset_x1_src, l_offset_y1_src; - OPJ_INT32 l_start_offset_src, l_line_offset_src, l_end_offset_src ; + size_t l_start_offset_src, l_line_offset_src, l_end_offset_src ; OPJ_UINT32 l_start_x_dest , l_start_y_dest; OPJ_UINT32 l_x0_dest, l_y0_dest, l_x1_dest, l_y1_dest; - OPJ_INT32 l_start_offset_dest, l_line_offset_dest; + size_t l_start_offset_dest, l_line_offset_dest; opj_image_comp_t * l_img_comp_src = 00; opj_image_comp_t * l_img_comp_dest = 00; @@ -7723,7 +8012,7 @@ OPJ_BOOL opj_j2k_update_image_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data, opj_im /* Allocate output component buffer if necessary */ if (!l_img_comp_dest->data) { - l_img_comp_dest->data = (OPJ_INT32*) opj_calloc(l_img_comp_dest->w * l_img_comp_dest->h, sizeof(OPJ_INT32)); + l_img_comp_dest->data = (OPJ_INT32*) opj_calloc((size_t)l_img_comp_dest->w * (size_t)l_img_comp_dest->h, sizeof(OPJ_INT32)); if (! l_img_comp_dest->data) { return OPJ_FALSE; } @@ -7790,7 +8079,7 @@ OPJ_BOOL opj_j2k_update_image_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data, opj_im } } else { - l_start_x_dest = 0 ; + l_start_x_dest = 0U; l_offset_x0_src = (OPJ_INT32)l_x0_dest - l_res->x0; if ( l_x1_dest >= (OPJ_UINT32)l_res->x1 ) { @@ -7817,7 +8106,7 @@ OPJ_BOOL opj_j2k_update_image_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data, opj_im } } else { - l_start_y_dest = 0 ; + l_start_y_dest = 0U; l_offset_y0_src = (OPJ_INT32)l_y0_dest - l_res->y0; if ( l_y1_dest >= (OPJ_UINT32)l_res->y1 ) { @@ -7840,13 +8129,13 @@ OPJ_BOOL opj_j2k_update_image_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data, opj_im /*-----*/ /* Compute the input buffer offset */ - l_start_offset_src = l_offset_x0_src + l_offset_y0_src * (OPJ_INT32)l_width_src; - l_line_offset_src = l_offset_x1_src + l_offset_x0_src; - l_end_offset_src = l_offset_y1_src * (OPJ_INT32)l_width_src - l_offset_x0_src; + l_start_offset_src = (size_t)l_offset_x0_src + (size_t)l_offset_y0_src * (size_t)l_width_src; + l_line_offset_src = (size_t)l_offset_x1_src + (size_t)l_offset_x0_src; + l_end_offset_src = (size_t)l_offset_y1_src * (size_t)l_width_src - (size_t)l_offset_x0_src; /* Compute the output buffer offset */ - l_start_offset_dest = (OPJ_INT32)(l_start_x_dest + l_start_y_dest * l_img_comp_dest->w); - l_line_offset_dest = (OPJ_INT32)(l_img_comp_dest->w - l_width_dest); + l_start_offset_dest = (size_t)l_start_x_dest + (size_t)l_start_y_dest * (size_t)l_img_comp_dest->w; + l_line_offset_dest = (size_t)l_img_comp_dest->w - (size_t)l_width_dest; /* Move the output buffer to the first place where we will write*/ l_dest_ptr = l_img_comp_dest->data + l_start_offset_dest; @@ -8112,23 +8401,21 @@ OPJ_BOOL opj_j2k_set_decode_area( opj_j2k_t *p_j2k, opj_j2k_t* opj_j2k_create_decompress(void) { - opj_j2k_t *l_j2k = (opj_j2k_t*) opj_malloc(sizeof(opj_j2k_t)); + opj_j2k_t *l_j2k = (opj_j2k_t*) opj_calloc(1,sizeof(opj_j2k_t)); if (!l_j2k) { return 00; } - memset(l_j2k,0,sizeof(opj_j2k_t)); l_j2k->m_is_decoder = 1; l_j2k->m_cp.m_is_decoder = 1; - l_j2k->m_specific_param.m_decoder.m_default_tcp = (opj_tcp_t*) opj_malloc(sizeof(opj_tcp_t)); + l_j2k->m_specific_param.m_decoder.m_default_tcp = (opj_tcp_t*) opj_calloc(1,sizeof(opj_tcp_t)); if (!l_j2k->m_specific_param.m_decoder.m_default_tcp) { opj_j2k_destroy(l_j2k); return 00; } - memset(l_j2k->m_specific_param.m_decoder.m_default_tcp,0,sizeof(opj_tcp_t)); - l_j2k->m_specific_param.m_decoder.m_header_data = (OPJ_BYTE *) opj_malloc(OPJ_J2K_DEFAULT_HEADER_SIZE); + l_j2k->m_specific_param.m_decoder.m_header_data = (OPJ_BYTE *) opj_calloc(1,OPJ_J2K_DEFAULT_HEADER_SIZE); if (! l_j2k->m_specific_param.m_decoder.m_header_data) { opj_j2k_destroy(l_j2k); return 00; @@ -8142,16 +8429,11 @@ opj_j2k_t* opj_j2k_create_decompress(void) /* codestream index creation */ l_j2k->cstr_index = opj_j2k_create_cstr_index(); - - /*(opj_codestream_index_t*) opj_malloc(sizeof(opj_codestream_index_t)); if (!l_j2k->cstr_index){ opj_j2k_destroy(l_j2k); - return NULL; + return 00; } - l_j2k->cstr_index->marker = (opj_marker_info_t*) opj_malloc(100 * sizeof(opj_marker_info_t)); -*/ - /* validation list creation */ l_j2k->m_validation_list = opj_procedure_list_create(); if (! l_j2k->m_validation_list) { @@ -8359,6 +8641,11 @@ OPJ_BOOL opj_j2k_read_SPCod_SPCoc( opj_j2k_t *p_j2k, for (i = 0; i < l_tccp->numresolutions; ++i) { opj_read_bytes(l_current_ptr,&l_tmp ,1); /* SPcoc (I_i) */ ++l_current_ptr; + /* Precinct exponent 0 is only allowed for lowest resolution level (Table A.21) */ + if ((i != 0) && (((l_tmp & 0xf) == 0) || ((l_tmp >> 4) == 0))) { + opj_event_msg(p_manager, EVT_ERROR, "Invalid precinct size\n"); + return OPJ_FALSE; + } l_tccp->prcw[i] = l_tmp & 0xf; l_tccp->prch[i] = l_tmp >> 4; } @@ -8676,6 +8963,58 @@ void opj_j2k_copy_tile_quantization_parameters( opj_j2k_t *p_j2k ) } } +static void opj_j2k_dump_tile_info( opj_tcp_t * l_default_tile,OPJ_INT32 numcomps,FILE* out_stream) +{ + if (l_default_tile) + { + OPJ_INT32 compno; + + fprintf(out_stream, "\t default tile {\n"); + fprintf(out_stream, "\t\t csty=%#x\n", l_default_tile->csty); + fprintf(out_stream, "\t\t prg=%#x\n", l_default_tile->prg); + fprintf(out_stream, "\t\t numlayers=%d\n", l_default_tile->numlayers); + fprintf(out_stream, "\t\t mct=%x\n", l_default_tile->mct); + + for (compno = 0; compno < numcomps; compno++) { + opj_tccp_t *l_tccp = &(l_default_tile->tccps[compno]); + OPJ_UINT32 resno; + OPJ_INT32 bandno, numbands; + + /* coding style*/ + fprintf(out_stream, "\t\t comp %d {\n", compno); + fprintf(out_stream, "\t\t\t csty=%#x\n", l_tccp->csty); + fprintf(out_stream, "\t\t\t numresolutions=%d\n", l_tccp->numresolutions); + fprintf(out_stream, "\t\t\t cblkw=2^%d\n", l_tccp->cblkw); + fprintf(out_stream, "\t\t\t cblkh=2^%d\n", l_tccp->cblkh); + fprintf(out_stream, "\t\t\t cblksty=%#x\n", l_tccp->cblksty); + fprintf(out_stream, "\t\t\t qmfbid=%d\n", l_tccp->qmfbid); + + fprintf(out_stream, "\t\t\t preccintsize (w,h)="); + for (resno = 0; resno < l_tccp->numresolutions; resno++) { + fprintf(out_stream, "(%d,%d) ", l_tccp->prcw[resno], l_tccp->prch[resno]); + } + fprintf(out_stream, "\n"); + + /* quantization style*/ + fprintf(out_stream, "\t\t\t qntsty=%d\n", l_tccp->qntsty); + fprintf(out_stream, "\t\t\t numgbits=%d\n", l_tccp->numgbits); + fprintf(out_stream, "\t\t\t stepsizes (m,e)="); + numbands = (l_tccp->qntsty == J2K_CCP_QNTSTY_SIQNT) ? 1 : (OPJ_INT32)l_tccp->numresolutions * 3 - 2; + for (bandno = 0; bandno < numbands; bandno++) { + fprintf(out_stream, "(%d,%d) ", l_tccp->stepsizes[bandno].mant, + l_tccp->stepsizes[bandno].expn); + } + fprintf(out_stream, "\n"); + + /* RGN value*/ + fprintf(out_stream, "\t\t\t roishift=%d\n", l_tccp->roishift); + + fprintf(out_stream, "\t\t }\n"); + } /*end of component of default tile*/ + fprintf(out_stream, "\t }\n"); /*end of default tile*/ + } +} + void j2k_dump (opj_j2k_t* p_j2k, OPJ_INT32 flag, FILE* out_stream) { /* Check if the flag is compatible with j2k file*/ @@ -8694,6 +9033,16 @@ void j2k_dump (opj_j2k_t* p_j2k, OPJ_INT32 flag, FILE* out_stream) if (flag & OPJ_J2K_MH_INFO){ opj_j2k_dump_MH_info(p_j2k, out_stream); } + /* Dump all tile/codestream info */ + if (flag & OPJ_J2K_TCH_INFO){ + OPJ_UINT32 l_nb_tiles = p_j2k->m_cp.th * p_j2k->m_cp.tw; + OPJ_UINT32 i; + opj_tcp_t * l_tcp = p_j2k->m_cp.tcps; + for (i=0;im_private_image->numcomps, out_stream); + ++l_tcp; + } + } /* Dump the codestream info of the current tile */ if (flag & OPJ_J2K_TH_INFO){ @@ -8780,70 +9129,17 @@ void opj_j2k_dump_MH_index(opj_j2k_t* p_j2k, FILE* out_stream) } + void opj_j2k_dump_MH_info(opj_j2k_t* p_j2k, FILE* out_stream) { - opj_tcp_t * l_default_tile=NULL; fprintf(out_stream, "Codestream info from main header: {\n"); fprintf(out_stream, "\t tx0=%d, ty0=%d\n", p_j2k->m_cp.tx0, p_j2k->m_cp.ty0); fprintf(out_stream, "\t tdx=%d, tdy=%d\n", p_j2k->m_cp.tdx, p_j2k->m_cp.tdy); fprintf(out_stream, "\t tw=%d, th=%d\n", p_j2k->m_cp.tw, p_j2k->m_cp.th); - - l_default_tile = p_j2k->m_specific_param.m_decoder.m_default_tcp; - if (l_default_tile) - { - OPJ_INT32 compno; - OPJ_INT32 numcomps = (OPJ_INT32)p_j2k->m_private_image->numcomps; - - fprintf(out_stream, "\t default tile {\n"); - fprintf(out_stream, "\t\t csty=%#x\n", l_default_tile->csty); - fprintf(out_stream, "\t\t prg=%#x\n", l_default_tile->prg); - fprintf(out_stream, "\t\t numlayers=%d\n", l_default_tile->numlayers); - fprintf(out_stream, "\t\t mct=%x\n", l_default_tile->mct); - - for (compno = 0; compno < numcomps; compno++) { - opj_tccp_t *l_tccp = &(l_default_tile->tccps[compno]); - OPJ_UINT32 resno; - OPJ_INT32 bandno, numbands; - - /* coding style*/ - fprintf(out_stream, "\t\t comp %d {\n", compno); - fprintf(out_stream, "\t\t\t csty=%#x\n", l_tccp->csty); - fprintf(out_stream, "\t\t\t numresolutions=%d\n", l_tccp->numresolutions); - fprintf(out_stream, "\t\t\t cblkw=2^%d\n", l_tccp->cblkw); - fprintf(out_stream, "\t\t\t cblkh=2^%d\n", l_tccp->cblkh); - fprintf(out_stream, "\t\t\t cblksty=%#x\n", l_tccp->cblksty); - fprintf(out_stream, "\t\t\t qmfbid=%d\n", l_tccp->qmfbid); - - fprintf(out_stream, "\t\t\t preccintsize (w,h)="); - for (resno = 0; resno < l_tccp->numresolutions; resno++) { - fprintf(out_stream, "(%d,%d) ", l_tccp->prcw[resno], l_tccp->prch[resno]); - } - fprintf(out_stream, "\n"); - - /* quantization style*/ - fprintf(out_stream, "\t\t\t qntsty=%d\n", l_tccp->qntsty); - fprintf(out_stream, "\t\t\t numgbits=%d\n", l_tccp->numgbits); - fprintf(out_stream, "\t\t\t stepsizes (m,e)="); - numbands = (l_tccp->qntsty == J2K_CCP_QNTSTY_SIQNT) ? 1 : (OPJ_INT32)l_tccp->numresolutions * 3 - 2; - for (bandno = 0; bandno < numbands; bandno++) { - fprintf(out_stream, "(%d,%d) ", l_tccp->stepsizes[bandno].mant, - l_tccp->stepsizes[bandno].expn); - } - fprintf(out_stream, "\n"); - - /* RGN value*/ - fprintf(out_stream, "\t\t\t roishift=%d\n", l_tccp->roishift); - - fprintf(out_stream, "\t\t }\n"); - } /*end of component of default tile*/ - fprintf(out_stream, "\t }\n"); /*end of default tile*/ - - } - + opj_j2k_dump_tile_info(p_j2k->m_specific_param.m_decoder.m_default_tcp,(OPJ_INT32)p_j2k->m_private_image->numcomps, out_stream); fprintf(out_stream, "}\n"); - } void j2k_dump_image_header(opj_image_t* img_header, OPJ_BOOL dev_dump_flag, FILE* out_stream) @@ -9323,7 +9619,7 @@ OPJ_BOOL opj_j2k_decode(opj_j2k_t * p_j2k, if (!p_image) return OPJ_FALSE; - + p_j2k->m_output_image = opj_image_create0(); if (! (p_j2k->m_output_image)) { return OPJ_FALSE; @@ -9484,50 +9780,82 @@ OPJ_BOOL opj_j2k_encode(opj_j2k_t * p_j2k, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager ) { - OPJ_UINT32 i; + OPJ_UINT32 i, j; OPJ_UINT32 l_nb_tiles; - OPJ_UINT32 l_max_tile_size, l_current_tile_size; - OPJ_BYTE * l_current_data; + OPJ_UINT32 l_max_tile_size = 0, l_current_tile_size; + OPJ_BYTE * l_current_data = 00; + opj_tcd_t* p_tcd = 00; /* 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) { - opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to encode all tiles\n"); - return OPJ_FALSE; - } - l_max_tile_size = 1000; + + p_tcd = p_j2k->m_tcd; 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) { - OPJ_BYTE *l_new_current_data = (OPJ_BYTE *) opj_realloc(l_current_data, l_current_tile_size); - if (! l_new_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; + /* if we only have one tile, then simply set tile component data equal to image component data */ + /* otherwise, allocate the data */ + for (j=0;jm_tcd->image->numcomps;++j) { + opj_tcd_tilecomp_t* l_tilec = p_tcd->tcd_image->tiles->comps + j; + if (l_nb_tiles == 1) { + opj_image_comp_t * l_img_comp = p_tcd->image->comps + j; + l_tilec->data = l_img_comp->data; + l_tilec->ownsData = OPJ_FALSE; + } else { + if(! opj_alloc_tile_component_data(l_tilec)) { + opj_event_msg(p_manager, EVT_ERROR, "Error allocating tile component data." ); + if (l_current_data) { + opj_free(l_current_data); + } + return OPJ_FALSE; + } + opj_alloc_tile_component_data(l_tilec); } - l_current_data = l_new_current_data; - l_max_tile_size = l_current_tile_size; } + l_current_tile_size = opj_tcd_get_encoded_tile_size(p_j2k->m_tcd); + if (l_nb_tiles > 1) { + 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; + } + + /* copy image data (32 bit) to l_current_data as contiguous, all-component, zero offset buffer */ + /* 32 bit components @ 8 bit precision get converted to 8 bit */ + /* 32 bit components @ 16 bit precision get converted to 16 bit */ + opj_j2k_get_tile_data(p_j2k->m_tcd,l_current_data); - opj_j2k_get_tile_data(p_j2k->m_tcd,l_current_data); + /* now copy this data into the tile component */ + if (! opj_tcd_copy_tile_data(p_j2k->m_tcd,l_current_data,l_current_tile_size)) { + opj_event_msg(p_manager, EVT_ERROR, "Size mismatch between tile data and sent data." ); + return OPJ_FALSE; + } + } - if (! opj_j2k_post_write_tile (p_j2k,l_current_data,l_current_tile_size,p_stream,p_manager)) { + if (! opj_j2k_post_write_tile (p_j2k,p_stream,p_manager)) { return OPJ_FALSE; } } - opj_free(l_current_data); + if (l_current_data) { + opj_free(l_current_data); + } return OPJ_TRUE; } @@ -9557,6 +9885,10 @@ OPJ_BOOL opj_j2k_start_compress(opj_j2k_t *p_j2k, assert(p_manager != 00); p_j2k->m_private_image = opj_image_create0(); + if (! p_j2k->m_private_image) { + opj_event_msg(p_manager, EVT_ERROR, "Failed to allocate image header." ); + return OPJ_FALSE; + } opj_copy_image_header(p_image, p_j2k->m_private_image); /* TODO_MSD: Find a better way */ @@ -9615,37 +9947,61 @@ OPJ_BOOL opj_j2k_pre_write_tile ( opj_j2k_t * p_j2k, return OPJ_TRUE; } +void opj_get_tile_dimensions(opj_image_t * l_image, + opj_tcd_tilecomp_t * l_tilec, + opj_image_comp_t * l_img_comp, + OPJ_UINT32* l_size_comp, + OPJ_UINT32* l_width, + OPJ_UINT32* l_height, + OPJ_UINT32* l_offset_x, + OPJ_UINT32* l_offset_y, + OPJ_UINT32* l_image_width, + OPJ_UINT32* l_stride, + OPJ_UINT32* l_tile_offset) { + OPJ_UINT32 l_remaining; + *l_size_comp = l_img_comp->prec >> 3; /* (/8) */ + l_remaining = l_img_comp->prec & 7; /* (%8) */ + if (l_remaining) { + *l_size_comp += 1; + } + + if (*l_size_comp == 3) { + *l_size_comp = 4; + } + + *l_width = (OPJ_UINT32)(l_tilec->x1 - l_tilec->x0); + *l_height = (OPJ_UINT32)(l_tilec->y1 - l_tilec->y0); + *l_offset_x = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)l_image->x0, (OPJ_INT32)l_img_comp->dx); + *l_offset_y = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)l_image->y0, (OPJ_INT32)l_img_comp->dy); + *l_image_width = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)l_image->x1 - (OPJ_INT32)l_image->x0, (OPJ_INT32)l_img_comp->dx); + *l_stride = *l_image_width - *l_width; + *l_tile_offset = ((OPJ_UINT32)l_tilec->x0 - *l_offset_x) + ((OPJ_UINT32)l_tilec->y0 - *l_offset_y) * *l_image_width; +} + void opj_j2k_get_tile_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data) { OPJ_UINT32 i,j,k = 0; - OPJ_UINT32 l_width,l_height,l_stride, l_offset_x,l_offset_y, l_image_width; - opj_image_comp_t * l_img_comp = 00; - opj_tcd_tilecomp_t * l_tilec = 00; - opj_image_t * l_image = 00; - OPJ_UINT32 l_size_comp, l_remaining; - OPJ_INT32 * l_src_ptr; - l_tilec = p_tcd->tcd_image->tiles->comps; - l_image = p_tcd->image; - l_img_comp = l_image->comps; for (i=0;iimage->numcomps;++i) { - l_size_comp = l_img_comp->prec >> 3; /* (/8) */ - l_remaining = l_img_comp->prec & 7; /* (%8) */ - if (l_remaining) { - ++l_size_comp; - } - - if (l_size_comp == 3) { - l_size_comp = 4; - } - - l_width = (OPJ_UINT32)(l_tilec->x1 - l_tilec->x0); - l_height = (OPJ_UINT32)(l_tilec->y1 - l_tilec->y0); - l_offset_x = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)l_image->x0, (OPJ_INT32)l_img_comp->dx); - l_offset_y = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)l_image->y0, (OPJ_INT32)l_img_comp->dy); - l_image_width = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)l_image->x1 - (OPJ_INT32)l_image->x0, (OPJ_INT32)l_img_comp->dx); - l_stride = l_image_width - l_width; - l_src_ptr = l_img_comp->data + ((OPJ_UINT32)l_tilec->x0 - l_offset_x) + ((OPJ_UINT32)l_tilec->y0 - l_offset_y) * l_image_width; + opj_image_t * l_image = p_tcd->image; + OPJ_INT32 * l_src_ptr; + opj_tcd_tilecomp_t * l_tilec = p_tcd->tcd_image->tiles->comps + i; + opj_image_comp_t * l_img_comp = l_image->comps + i; + OPJ_UINT32 l_size_comp,l_width,l_height,l_offset_x,l_offset_y, l_image_width,l_stride,l_tile_offset; + + opj_get_tile_dimensions(l_image, + l_tilec, + l_img_comp, + &l_size_comp, + &l_width, + &l_height, + &l_offset_x, + &l_offset_y, + &l_image_width, + &l_stride, + &l_tile_offset); + + l_src_ptr = l_img_comp->data + l_tile_offset; switch (l_size_comp) { case 1: @@ -9712,19 +10068,13 @@ void opj_j2k_get_tile_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data) } break; } - - ++l_img_comp; - ++l_tilec; } } OPJ_BOOL opj_j2k_post_write_tile ( opj_j2k_t * p_j2k, - OPJ_BYTE * p_data, - OPJ_UINT32 p_data_size, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager ) { - opj_tcd_t * l_tcd = 00; OPJ_UINT32 l_nb_bytes_written; OPJ_BYTE * l_current_data = 00; OPJ_UINT32 l_tile_size = 0; @@ -9733,17 +10083,10 @@ OPJ_BOOL opj_j2k_post_write_tile ( opj_j2k_t * p_j2k, /* preconditions */ assert(p_j2k->m_specific_param.m_encoder.m_encoded_tile_data); - l_tcd = p_j2k->m_tcd; - l_tile_size = p_j2k->m_specific_param.m_encoder.m_encoded_tile_size; l_available_data = l_tile_size; l_current_data = p_j2k->m_specific_param.m_encoder.m_encoded_tile_data; - if (! opj_tcd_copy_tile_data(l_tcd,p_data,p_data_size)) { - opj_event_msg(p_manager, EVT_ERROR, "Size mismatch between tile data and sent data." ); - return OPJ_FALSE; - } - l_nb_bytes_written = 0; if (! opj_j2k_write_first_tile_part(p_j2k,l_current_data,&l_nb_bytes_written,l_available_data,p_stream,p_manager)) { return OPJ_FALSE; @@ -9778,7 +10121,7 @@ void opj_j2k_setup_end_compress (opj_j2k_t *p_j2k) /* DEVELOPER CORNER, insert your custom procedures */ opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_eoc ); - if (p_j2k->m_cp.m_specific_param.m_enc.m_cinema) { + if (OPJ_IS_CINEMA(p_j2k->m_cp.rsiz)) { opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_updated_tlm); } @@ -9810,14 +10153,14 @@ void opj_j2k_setup_header_writing (opj_j2k_t *p_j2k) opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_cod ); opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_qcd ); - if (p_j2k->m_cp.m_specific_param.m_enc.m_cinema) { + if (OPJ_IS_CINEMA(p_j2k->m_cp.rsiz)) { /* No need for COC or QCC, QCD and COD are used opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_all_coc ); opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_all_qcc ); */ opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_tlm ); - if (p_j2k->m_cp.m_specific_param.m_enc.m_cinema == OPJ_CINEMA4K_24) { + if (p_j2k->m_cp.rsiz == OPJ_PROFILE_CINEMA_4K) { opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_poc ); } } @@ -9829,7 +10172,7 @@ void opj_j2k_setup_header_writing (opj_j2k_t *p_j2k) } /* DEVELOPER CORNER, insert your custom procedures */ - if (p_j2k->m_cp.rsiz & OPJ_MCT) { + if (p_j2k->m_cp.rsiz & OPJ_EXTENSION_MCT) { opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_mct_data_group ); } /* End of Developer Corner */ @@ -9878,7 +10221,7 @@ OPJ_BOOL opj_j2k_write_first_tile_part (opj_j2k_t *p_j2k, p_data += l_current_nb_bytes_written; p_total_data_size -= l_current_nb_bytes_written; - if (l_cp->m_specific_param.m_enc.m_cinema == 0) { + if (!OPJ_IS_CINEMA(l_cp->rsiz)) { #if 0 for (compno = 1; compno < p_j2k->m_private_image->numcomps; compno++) { l_current_nb_bytes_written = 0; @@ -9915,7 +10258,7 @@ OPJ_BOOL opj_j2k_write_first_tile_part (opj_j2k_t *p_j2k, /* Writing Psot in SOT marker */ opj_write_bytes(l_begin_data + 6,l_nb_bytes_written,4); /* PSOT */ - if (l_cp->m_specific_param.m_enc.m_cinema){ + if (OPJ_IS_CINEMA(l_cp->rsiz)){ opj_j2k_update_tlm(p_j2k,l_nb_bytes_written); } @@ -9979,7 +10322,7 @@ OPJ_BOOL opj_j2k_write_all_tile_parts( opj_j2k_t *p_j2k, /* Writing Psot in SOT marker */ opj_write_bytes(l_begin_data + 6,l_part_tile_size,4); /* PSOT */ - if (l_cp->m_specific_param.m_enc.m_cinema) { + if (OPJ_IS_CINEMA(l_cp->rsiz)) { opj_j2k_update_tlm(p_j2k,l_part_tile_size); } @@ -10020,7 +10363,7 @@ OPJ_BOOL opj_j2k_write_all_tile_parts( opj_j2k_t *p_j2k, /* Writing Psot in SOT marker */ opj_write_bytes(l_begin_data + 6,l_part_tile_size,4); /* PSOT */ - if (l_cp->m_specific_param.m_enc.m_cinema) { + if (OPJ_IS_CINEMA(l_cp->rsiz)) { opj_j2k_update_tlm(p_j2k,l_part_tile_size); } @@ -10214,7 +10557,23 @@ OPJ_BOOL opj_j2k_write_tile (opj_j2k_t * p_j2k, return OPJ_FALSE; } else { - if (! opj_j2k_post_write_tile(p_j2k,p_data,p_data_size,p_stream,p_manager)) { + OPJ_UINT32 j; + /* Allocate data */ + for (j=0;jm_tcd->image->numcomps;++j) { + opj_tcd_tilecomp_t* l_tilec = p_j2k->m_tcd->tcd_image->tiles->comps + j; + + if(! opj_alloc_tile_component_data(l_tilec)) { + opj_event_msg(p_manager, EVT_ERROR, "Error allocating tile component data." ); + return OPJ_FALSE; + } + } + + /* now copy data into the the tile component */ + if (! opj_tcd_copy_tile_data(p_j2k->m_tcd,p_data,p_data_size)) { + opj_event_msg(p_manager, EVT_ERROR, "Size mismatch between tile data and sent data." ); + return OPJ_FALSE; + } + if (! opj_j2k_post_write_tile(p_j2k,p_stream,p_manager)) { opj_event_msg(p_manager, EVT_ERROR, "Error while opj_j2k_post_write_tile with tile index = %d\n", p_tile_index); return OPJ_FALSE; }