diff --git a/src/bin/jp2/opj_compress.c b/src/bin/jp2/opj_compress.c index cd3953e9..cbc30fba 100644 --- a/src/bin/jp2/opj_compress.c +++ b/src/bin/jp2/opj_compress.c @@ -229,6 +229,8 @@ static void encode_help_display(void) fprintf(stdout, " Write SOP marker before each packet.\n"); fprintf(stdout, "-EPH\n"); fprintf(stdout, " Write EPH marker after each header packet.\n"); + fprintf(stdout, "-PLT\n"); + fprintf(stdout, " Write PLT marker in tile-part header.\n"); fprintf(stdout, "-M \n"); fprintf(stdout, " Mode switch.\n"); fprintf(stdout, " [1=BYPASS(LAZY) 2=RESET 4=RESTART(TERMALL)\n"); @@ -576,7 +578,8 @@ static int parse_cmdline_encoder(int argc, char **argv, opj_cparameters_t *parameters, img_fol_t *img_fol, raw_cparameters_t *raw_cp, char *indexfilename, size_t indexfilename_size, - int* pOutFramerate) + int* pOutFramerate, + OPJ_BOOL* pOutPLT) { OPJ_UINT32 i, j; int totlen, c; @@ -592,7 +595,8 @@ static int parse_cmdline_encoder(int argc, char **argv, {"ROI", REQ_ARG, NULL, 'R'}, {"jpip", NO_ARG, NULL, 'J'}, {"mct", REQ_ARG, NULL, 'Y'}, - {"IMF", REQ_ARG, NULL, 'Z'} + {"IMF", REQ_ARG, NULL, 'Z'}, + {"PLT", NO_ARG, NULL, 'A'} }; /* parse the command line */ @@ -1670,6 +1674,13 @@ static int parse_cmdline_encoder(int argc, char **argv, break; /* ------------------------------------------------------ */ + case 'A': { /* PLT markers */ + *pOutPLT = OPJ_TRUE; + } + break; + + /* ------------------------------------------------------ */ + default: fprintf(stderr, "[WARNING] An invalid option has been ignored\n"); @@ -1848,6 +1859,8 @@ int main(int argc, char **argv) int framerate = 0; OPJ_FLOAT64 t = opj_clock(); + OPJ_BOOL PLT = OPJ_FALSE; + /* set encoding parameters to default values */ opj_set_default_encoder_parameters(¶meters); @@ -1867,7 +1880,7 @@ int main(int argc, char **argv) parameters.tcp_mct = (char) 255; /* This will be set later according to the input image or the provided option */ if (parse_cmdline_encoder(argc, argv, ¶meters, &img_fol, &raw_cp, - indexfilename, sizeof(indexfilename), &framerate) == 1) { + indexfilename, sizeof(indexfilename), &framerate, &PLT) == 1) { ret = 1; goto fin; } @@ -2117,6 +2130,17 @@ int main(int argc, char **argv) goto fin; } + if (PLT) { + const char* const options[] = { "PLT=YES", NULL }; + if (!opj_encoder_set_extra_options(l_codec, options)) { + fprintf(stderr, "failed to encode image: opj_encoder_set_extra_options\n"); + opj_destroy_codec(l_codec); + opj_image_destroy(image); + ret = 1; + goto fin; + } + } + /* 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) { diff --git a/src/lib/openjp2/j2k.c b/src/lib/openjp2/j2k.c index b16b8fe0..842c8caa 100644 --- a/src/lib/openjp2/j2k.c +++ b/src/lib/openjp2/j2k.c @@ -879,6 +879,8 @@ static OPJ_BOOL opj_j2k_read_sot(opj_j2k_t *p_j2k, /** * Writes the SOD marker (Start of data) * + * This also writes optional PLT markers (before SOD) + * * @param p_j2k J2K codec. * @param p_tile_coder FIXME DOC * @param p_data FIXME DOC @@ -3443,6 +3445,28 @@ static OPJ_UINT32 opj_j2k_get_specific_header_sizes(opj_j2k_t *p_j2k) l_nb_bytes += opj_j2k_get_max_poc_size(p_j2k); + if (p_j2k->m_specific_param.m_encoder.m_PLT) { + /* Reserve space for PLT markers */ + + OPJ_UINT32 i; + const opj_cp_t * l_cp = &(p_j2k->m_cp); + OPJ_UINT32 l_max_packet_count = 0; + for (i = 0; i < l_cp->th * l_cp->tw; ++i) { + l_max_packet_count = opj_uint_max(l_max_packet_count, + opj_get_encoding_packet_count(p_j2k->m_private_image, l_cp, i)); + } + /* Minimum 6 bytes per PLT marker, and at a minimum (taking a pessimistic */ + /* estimate of 4 bytes for a packet size), one can write */ + /* (65536-6) / 4 = 16382 paquet sizes per PLT marker */ + p_j2k->m_specific_param.m_encoder.m_reserved_bytes_for_PLT = + 6 * opj_uint_ceildiv(l_max_packet_count, 16382); + /* Maximum 5 bytes per packet to encode a full UINT32 */ + p_j2k->m_specific_param.m_encoder.m_reserved_bytes_for_PLT += + l_nb_bytes += 5 * l_max_packet_count; + p_j2k->m_specific_param.m_encoder.m_reserved_bytes_for_PLT += 1; + l_nb_bytes += p_j2k->m_specific_param.m_encoder.m_reserved_bytes_for_PLT; + } + /*** DEVELOPER CORNER, Add room for your headers ***/ return l_nb_bytes; @@ -4602,6 +4626,93 @@ static OPJ_BOOL opj_j2k_read_sot(opj_j2k_t *p_j2k, return OPJ_TRUE; } +/** + * Write one or more PLT markers in the provided buffer + */ +static OPJ_BOOL opj_j2k_write_plt_in_memory(opj_j2k_t *p_j2k, + opj_tcd_marker_info_t* marker_info, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + opj_event_mgr_t * p_manager) +{ + OPJ_BYTE Zplt = 0; + OPJ_UINT16 Lplt; + OPJ_BYTE* p_data_start = p_data; + OPJ_BYTE* p_data_Lplt = p_data + 2; + OPJ_UINT32 i; + + OPJ_UNUSED(p_j2k); + + opj_write_bytes(p_data, J2K_MS_PLT, 2); + p_data += 2; + + /* Reserve space for Lplt */ + p_data += 2; + + opj_write_bytes(p_data, Zplt, 1); + p_data += 1; + + Lplt = 3; + + for (i = 0; i < marker_info->packet_count; i++) { + OPJ_BYTE var_bytes[5]; + OPJ_UINT8 var_bytes_size = 0; + OPJ_UINT32 packet_size = marker_info->p_packet_size[i]; + + /* Packet size written in variable-length way, starting with LSB */ + var_bytes[var_bytes_size] = (OPJ_BYTE)(packet_size & 0x7f); + var_bytes_size ++; + packet_size >>= 7; + while (packet_size > 0) { + var_bytes[var_bytes_size] = (OPJ_BYTE)((packet_size & 0x7f) | 0x80); + var_bytes_size ++; + packet_size >>= 7; + } + + /* Check if that can fit in the current PLT marker. If not, finish */ + /* current one, and start a new one */ + if (Lplt + var_bytes_size > 65535) { + if (Zplt == 255) { + opj_event_msg(p_manager, EVT_ERROR, + "More than 255 PLT markers would be needed for current tile-part !\n"); + return OPJ_FALSE; + } + + /* Patch Lplt */ + opj_write_bytes(p_data_Lplt, Lplt, 2); + + /* Start new segment */ + opj_write_bytes(p_data, J2K_MS_PLT, 2); + p_data += 2; + + /* Reserve space for Lplt */ + p_data_Lplt = p_data; + p_data += 2; + + Zplt ++; + opj_write_bytes(p_data, Zplt, 1); + p_data += 1; + + Lplt = 3; + } + + Lplt = (OPJ_UINT16)(Lplt + var_bytes_size); + + /* Serialize variable-length packet size, starting with MSB */ + for (; var_bytes_size > 0; --var_bytes_size) { + opj_write_bytes(p_data, var_bytes[var_bytes_size - 1], 1); + p_data += 1; + } + } + + *p_data_written = (OPJ_UINT32)(p_data - p_data_start); + + /* Patch Lplt */ + opj_write_bytes(p_data_Lplt, Lplt, 2); + + return OPJ_TRUE; +} + static OPJ_BOOL opj_j2k_write_sod(opj_j2k_t *p_j2k, opj_tcd_t * p_tile_coder, OPJ_BYTE * p_data, @@ -4613,6 +4724,7 @@ static OPJ_BOOL opj_j2k_write_sod(opj_j2k_t *p_j2k, { opj_codestream_info_t *l_cstr_info = 00; OPJ_UINT32 l_remaining_data; + opj_tcd_marker_info_t* marker_info = NULL; /* preconditions */ assert(p_j2k != 00); @@ -4629,7 +4741,6 @@ static OPJ_BOOL opj_j2k_write_sod(opj_j2k_t *p_j2k, opj_write_bytes(p_data, J2K_MS_SOD, 2); /* SOD */ - p_data += 2; /* make room for the EOF marker */ l_remaining_data = total_data_size - 4; @@ -4679,15 +4790,64 @@ static OPJ_BOOL opj_j2k_write_sod(opj_j2k_t *p_j2k, *p_data_written = 0; - if (! opj_tcd_encode_tile(p_tile_coder, p_j2k->m_current_tile_number, p_data, + if (p_j2k->m_specific_param.m_encoder.m_PLT) { + marker_info = opj_tcd_marker_info_create( + p_j2k->m_specific_param.m_encoder.m_PLT); + if (marker_info == NULL) { + opj_event_msg(p_manager, EVT_ERROR, + "Cannot encode tile: opj_tcd_marker_info_create() failed\n"); + return OPJ_FALSE; + } + } + + assert(l_remaining_data > + p_j2k->m_specific_param.m_encoder.m_reserved_bytes_for_PLT); + l_remaining_data -= p_j2k->m_specific_param.m_encoder.m_reserved_bytes_for_PLT; + + if (! opj_tcd_encode_tile(p_tile_coder, p_j2k->m_current_tile_number, + p_data + 2, p_data_written, l_remaining_data, l_cstr_info, + marker_info, p_manager)) { opj_event_msg(p_manager, EVT_ERROR, "Cannot encode tile\n"); + opj_tcd_marker_info_destroy(marker_info); return OPJ_FALSE; } + /* For SOD */ *p_data_written += 2; + if (p_j2k->m_specific_param.m_encoder.m_PLT) { + OPJ_UINT32 l_data_written_PLT = 0; + OPJ_BYTE* p_PLT_buffer = (OPJ_BYTE*)opj_malloc( + p_j2k->m_specific_param.m_encoder.m_reserved_bytes_for_PLT); + if (!p_PLT_buffer) { + opj_event_msg(p_manager, EVT_ERROR, "Cannot allocate memory\n"); + opj_tcd_marker_info_destroy(marker_info); + return OPJ_FALSE; + } + if (!opj_j2k_write_plt_in_memory(p_j2k, + marker_info, + p_PLT_buffer, + &l_data_written_PLT, + p_manager)) { + opj_tcd_marker_info_destroy(marker_info); + opj_free(p_PLT_buffer); + return OPJ_FALSE; + } + + assert(l_data_written_PLT <= + p_j2k->m_specific_param.m_encoder.m_reserved_bytes_for_PLT); + + /* Move PLT marker(s) before SOD */ + memmove(p_data + l_data_written_PLT, p_data, *p_data_written); + memcpy(p_data, p_PLT_buffer, l_data_written_PLT); + opj_free(p_PLT_buffer); + *p_data_written += l_data_written_PLT; + } + + opj_tcd_marker_info_destroy(marker_info); + return OPJ_TRUE; } @@ -11819,6 +11979,42 @@ OPJ_BOOL opj_j2k_set_decoded_resolution_factor(opj_j2k_t *p_j2k, return OPJ_FALSE; } +/* ----------------------------------------------------------------------- */ + +OPJ_BOOL opj_j2k_encoder_set_extra_options( + opj_j2k_t *p_j2k, + const char* const* p_options, + opj_event_mgr_t * p_manager) +{ + const char* const* p_option_iter; + + if (p_options == NULL) { + return OPJ_TRUE; + } + + for (p_option_iter = p_options; *p_option_iter != NULL; ++p_option_iter) { + if (strncmp(*p_option_iter, "PLT=", 4) == 0) { + if (strcmp(*p_option_iter, "PLT=YES") == 0) { + p_j2k->m_specific_param.m_encoder.m_PLT = OPJ_TRUE; + } else if (strcmp(*p_option_iter, "PLT=NO") == 0) { + p_j2k->m_specific_param.m_encoder.m_PLT = OPJ_FALSE; + } else { + opj_event_msg(p_manager, EVT_ERROR, + "Invalid value for option: %s.\n", *p_option_iter); + return OPJ_FALSE; + } + } else { + opj_event_msg(p_manager, EVT_ERROR, + "Invalid option: %s.\n", *p_option_iter); + return OPJ_FALSE; + } + } + + return OPJ_TRUE; +} + +/* ----------------------------------------------------------------------- */ + OPJ_BOOL opj_j2k_encode(opj_j2k_t * p_j2k, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager) diff --git a/src/lib/openjp2/j2k.h b/src/lib/openjp2/j2k.h index 3ea6395f..9eb50b50 100644 --- a/src/lib/openjp2/j2k.h +++ b/src/lib/openjp2/j2k.h @@ -531,8 +531,14 @@ typedef struct opj_j2k_enc { OPJ_BYTE * m_header_tile_data; /* size of the encoded_data */ + OPJ_UINT32 m_header_tile_data_size; + /* whether to generate PLT markers */ + OPJ_BOOL m_PLT; + + /* reserved bytes in m_encoded_tile_size for PLT markers */ + OPJ_UINT32 m_reserved_bytes_for_PLT; } opj_j2k_enc_t; @@ -828,6 +834,19 @@ OPJ_BOOL opj_j2k_set_decoded_resolution_factor(opj_j2k_t *p_j2k, OPJ_UINT32 res_factor, opj_event_mgr_t * p_manager); +/** + * Specify extra options for the encoder. + * + * @param p_j2k the jpeg2000 codec. + * @param p_options options + * @param p_manager the user event manager + * + * @see opj_encoder_set_extra_options() for more details. + */ +OPJ_BOOL opj_j2k_encoder_set_extra_options( + opj_j2k_t *p_j2k, + const char* const* p_options, + opj_event_mgr_t * p_manager); /** * Writes a tile. diff --git a/src/lib/openjp2/jp2.c b/src/lib/openjp2/jp2.c index a2363666..4809e348 100644 --- a/src/lib/openjp2/jp2.c +++ b/src/lib/openjp2/jp2.c @@ -3234,6 +3234,18 @@ OPJ_BOOL opj_jp2_set_decoded_resolution_factor(opj_jp2_t *p_jp2, return opj_j2k_set_decoded_resolution_factor(p_jp2->j2k, res_factor, p_manager); } +/* ----------------------------------------------------------------------- */ + +OPJ_BOOL opj_jp2_encoder_set_extra_options( + opj_jp2_t *p_jp2, + const char* const* p_options, + opj_event_mgr_t * p_manager) +{ + return opj_j2k_encoder_set_extra_options(p_jp2->j2k, p_options, p_manager); +} + +/* ----------------------------------------------------------------------- */ + /* JPIP specific */ #ifdef USE_JPIP diff --git a/src/lib/openjp2/jp2.h b/src/lib/openjp2/jp2.h index 34abd511..9e7fa566 100644 --- a/src/lib/openjp2/jp2.h +++ b/src/lib/openjp2/jp2.h @@ -459,6 +459,20 @@ OPJ_BOOL opj_jp2_set_decoded_resolution_factor(opj_jp2_t *p_jp2, OPJ_UINT32 res_factor, opj_event_mgr_t * p_manager); +/** + * Specify extra options for the encoder. + * + * @param p_jp2 the jpeg2000 codec. + * @param p_options options + * @param p_manager the user event manager + * + * @see opj_encoder_set_extra_options() for more details. + */ +OPJ_BOOL opj_jp2_encoder_set_extra_options( + opj_jp2_t *p_jp2, + const char* const* p_options, + opj_event_mgr_t * p_manager); + /* TODO MSD: clean these 3 functions */ /** diff --git a/src/lib/openjp2/openjpeg.c b/src/lib/openjp2/openjpeg.c index e406cb49..1e2d60a6 100644 --- a/src/lib/openjp2/openjpeg.c +++ b/src/lib/openjp2/openjpeg.c @@ -652,6 +652,11 @@ opj_codec_t* OPJ_CALLCONV opj_create_compress(OPJ_CODEC_FORMAT p_format) struct opj_image *, struct opj_event_mgr *)) opj_j2k_setup_encoder; + l_codec->m_codec_data.m_compression.opj_encoder_set_extra_options = (OPJ_BOOL( + *)(void *, + const char* const*, + struct opj_event_mgr *)) opj_j2k_encoder_set_extra_options; + l_codec->m_codec = opj_j2k_create_compress(); if (! l_codec->m_codec) { opj_free(l_codec); @@ -690,6 +695,11 @@ opj_codec_t* OPJ_CALLCONV opj_create_compress(OPJ_CODEC_FORMAT p_format) struct opj_image *, struct opj_event_mgr *)) opj_jp2_setup_encoder; + l_codec->m_codec_data.m_compression.opj_encoder_set_extra_options = (OPJ_BOOL( + *)(void *, + const char* const*, + struct opj_event_mgr *)) opj_jp2_encoder_set_extra_options; + l_codec->m_codec = opj_jp2_create(OPJ_FALSE); if (! l_codec->m_codec) { opj_free(l_codec); @@ -788,6 +798,27 @@ OPJ_BOOL OPJ_CALLCONV opj_setup_encoder(opj_codec_t *p_codec, return OPJ_FALSE; } +/* ----------------------------------------------------------------------- */ + +OPJ_BOOL OPJ_CALLCONV opj_encoder_set_extra_options(opj_codec_t *p_codec, + const char* const* options) +{ + if (p_codec) { + opj_codec_private_t * l_codec = (opj_codec_private_t *) p_codec; + + if (! l_codec->is_decompressor) { + return l_codec->m_codec_data.m_compression.opj_encoder_set_extra_options( + l_codec->m_codec, + options, + &(l_codec->m_event_mgr)); + } + } + + return OPJ_FALSE; +} + +/* ----------------------------------------------------------------------- */ + OPJ_BOOL OPJ_CALLCONV opj_start_compress(opj_codec_t *p_codec, opj_image_t * p_image, opj_stream_t *p_stream) diff --git a/src/lib/openjp2/openjpeg.h b/src/lib/openjp2/openjpeg.h index 3b773e97..da84f399 100644 --- a/src/lib/openjp2/openjpeg.h +++ b/src/lib/openjp2/openjpeg.h @@ -1580,6 +1580,33 @@ OPJ_API OPJ_BOOL OPJ_CALLCONV opj_setup_encoder(opj_codec_t *p_codec, opj_cparameters_t *parameters, opj_image_t *image); + +/** + * Specify extra options for the encoder. + * + * This may be called after opj_setup_encoder() and before opj_start_compress() + * + * This is the way to add new options in a fully ABI compatible way, without + * extending the opj_cparameters_t structure. + * + * Currently supported options are: + * + * + * @param p_codec Compressor handle + * @param p_options Compression options. This should be a NULL terminated + * array of strings. Each string is of the form KEY=VALUE. + * + * @return OPJ_TRUE in case of success. + * @since 2.3.2 + */ +OPJ_API OPJ_BOOL OPJ_CALLCONV opj_encoder_set_extra_options( + opj_codec_t *p_codec, + const char* const* p_options); + /** * Start to compress the current image. * @param p_codec Compressor handle diff --git a/src/lib/openjp2/opj_codec.h b/src/lib/openjp2/opj_codec.h index b962b121..8a8af911 100644 --- a/src/lib/openjp2/opj_codec.h +++ b/src/lib/openjp2/opj_codec.h @@ -148,6 +148,11 @@ typedef struct opj_codec_private { opj_cparameters_t * p_param, struct opj_image * p_image, struct opj_event_mgr * p_manager); + + OPJ_BOOL(* opj_encoder_set_extra_options)(void * p_codec, + const char* const* p_options, + struct opj_event_mgr * p_manager); + } m_compression; } m_codec_data; /** FIXME DOC*/ diff --git a/src/lib/openjp2/pi.c b/src/lib/openjp2/pi.c index 7debc774..3dcdd4e9 100644 --- a/src/lib/openjp2/pi.c +++ b/src/lib/openjp2/pi.c @@ -920,7 +920,7 @@ static void opj_get_all_encoding_parameters(const opj_image_t *p_image, OPJ_UINT32 l_tcx0, l_tcy0, l_tcx1, l_tcy1; OPJ_UINT32 l_pdx, l_pdy, l_pw, l_ph; - lResolutionPtr = p_resolutions[compno]; + lResolutionPtr = p_resolutions ? p_resolutions[compno] : NULL; l_tcx0 = opj_uint_ceildiv(*p_tx0, l_img_comp->dx); l_tcy0 = opj_uint_ceildiv(*p_ty0, l_img_comp->dy); @@ -941,8 +941,10 @@ static void opj_get_all_encoding_parameters(const opj_image_t *p_image, /* precinct width and height*/ l_pdx = l_tccp->prcw[resno]; l_pdy = l_tccp->prch[resno]; - *lResolutionPtr++ = l_pdx; - *lResolutionPtr++ = l_pdy; + if (lResolutionPtr) { + *lResolutionPtr++ = l_pdx; + *lResolutionPtr++ = l_pdy; + } if (l_pdx + l_level_no < 32 && l_img_comp->dx <= UINT_MAX / (1u << (l_pdx + l_level_no))) { l_dx = l_img_comp->dx * (1u << (l_pdx + l_level_no)); @@ -966,8 +968,10 @@ static void opj_get_all_encoding_parameters(const opj_image_t *p_image, py1 = opj_uint_ceildivpow2(l_ry1, l_pdy) << l_pdy; l_pw = (l_rx0 == l_rx1) ? 0 : ((l_px1 - l_px0) >> l_pdx); l_ph = (l_ry0 == l_ry1) ? 0 : ((py1 - l_py0) >> l_pdy); - *lResolutionPtr++ = l_pw; - *lResolutionPtr++ = l_ph; + if (lResolutionPtr) { + *lResolutionPtr++ = l_pw; + *lResolutionPtr++ = l_ph; + } l_product = l_pw * l_ph; /* update precision*/ @@ -1550,6 +1554,28 @@ opj_pi_iterator_t *opj_pi_create_decode(opj_image_t *p_image, } +OPJ_UINT32 opj_get_encoding_packet_count(const opj_image_t *p_image, + const opj_cp_t *p_cp, + OPJ_UINT32 p_tile_no) +{ + OPJ_UINT32 l_max_res; + OPJ_UINT32 l_max_prec; + OPJ_UINT32 l_tx0, l_tx1, l_ty0, l_ty1; + OPJ_UINT32 l_dx_min, l_dy_min; + + /* preconditions in debug*/ + assert(p_cp != 00); + assert(p_image != 00); + assert(p_tile_no < p_cp->tw * p_cp->th); + + /* get encoding parameters*/ + opj_get_all_encoding_parameters(p_image, p_cp, p_tile_no, &l_tx0, &l_tx1, + &l_ty0, &l_ty1, &l_dx_min, &l_dy_min, &l_max_prec, &l_max_res, NULL); + + return p_cp->tcps[p_tile_no].numlayers * l_max_prec * p_image->numcomps * + l_max_res; +} + opj_pi_iterator_t *opj_pi_initialise_encode(const opj_image_t *p_image, opj_cp_t *p_cp, diff --git a/src/lib/openjp2/pi.h b/src/lib/openjp2/pi.h index 87380208..7fb3417f 100644 --- a/src/lib/openjp2/pi.h +++ b/src/lib/openjp2/pi.h @@ -182,6 +182,17 @@ Modify the packet iterator to point to the next packet @return Returns false if pi pointed to the last packet or else returns true */ OPJ_BOOL opj_pi_next(opj_pi_iterator_t * pi); + +/** + * Return the number of packets in the tile. + * @param image the image being encoded. + * @param cp Coding parameters + * @param tileno Number that identifies the tile. + */ +OPJ_UINT32 opj_get_encoding_packet_count(const opj_image_t *p_image, + const opj_cp_t *p_cp, + OPJ_UINT32 p_tile_no); + /* ----------------------------------------------------------------------- */ /*@}*/ diff --git a/src/lib/openjp2/t2.c b/src/lib/openjp2/t2.c index 0887b9f5..71472b49 100644 --- a/src/lib/openjp2/t2.c +++ b/src/lib/openjp2/t2.c @@ -224,6 +224,7 @@ OPJ_BOOL opj_t2_encode_packets(opj_t2_t* p_t2, OPJ_UINT32 * p_data_written, OPJ_UINT32 p_max_len, opj_codestream_info_t *cstr_info, + opj_tcd_marker_info_t* p_marker_info, OPJ_UINT32 p_tp_num, OPJ_INT32 p_tp_pos, OPJ_UINT32 p_pino, @@ -310,6 +311,20 @@ OPJ_BOOL opj_t2_encode_packets(opj_t2_t* p_t2, opj_pi_destroy(l_pi, l_nb_pocs); return OPJ_FALSE; } + + if (p_marker_info && p_marker_info->need_PLT) { + /* One time use intended */ + assert(p_marker_info->packet_count == 0); + assert(p_marker_info->p_packet_size == NULL); + + p_marker_info->p_packet_size = (OPJ_UINT32*) opj_malloc( + opj_get_encoding_packet_count(l_image, l_cp, p_tile_no) * sizeof(OPJ_UINT32)); + if (p_marker_info->p_packet_size == NULL) { + 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; @@ -326,6 +341,11 @@ OPJ_BOOL opj_t2_encode_packets(opj_t2_t* p_t2, * p_data_written += l_nb_bytes; + if (p_marker_info && p_marker_info->need_PLT) { + p_marker_info->p_packet_size[p_marker_info->packet_count] = l_nb_bytes; + p_marker_info->packet_count ++; + } + /* INDEX >> */ if (cstr_info) { if (cstr_info->index_write) { diff --git a/src/lib/openjp2/t2.h b/src/lib/openjp2/t2.h index 66500b16..becfa91a 100644 --- a/src/lib/openjp2/t2.h +++ b/src/lib/openjp2/t2.h @@ -73,6 +73,7 @@ Encode the packets of a tile to a destination buffer @param p_data_written FIXME DOC @param len the length of the destination buffer @param cstr_info Codestream information structure +@param p_marker_info Marker information structure @param tpnum Tile part number of the current tile @param tppos The position of the tile part flag in the progression order @param pino FIXME DOC @@ -87,6 +88,7 @@ OPJ_BOOL opj_t2_encode_packets(opj_t2_t* t2, OPJ_UINT32 * p_data_written, OPJ_UINT32 len, opj_codestream_info_t *cstr_info, + opj_tcd_marker_info_t* p_marker_info, OPJ_UINT32 tpnum, OPJ_INT32 tppos, OPJ_UINT32 pino, diff --git a/src/lib/openjp2/tcd.c b/src/lib/openjp2/tcd.c index bca82423..3a1c3026 100644 --- a/src/lib/openjp2/tcd.c +++ b/src/lib/openjp2/tcd.c @@ -182,6 +182,7 @@ static OPJ_BOOL opj_tcd_t2_encode(opj_tcd_t *p_tcd, OPJ_UINT32 * p_data_written, OPJ_UINT32 p_max_dest_size, opj_codestream_info_t *p_cstr_info, + opj_tcd_marker_info_t* p_marker_info, opj_event_mgr_t *p_manager); static OPJ_BOOL opj_tcd_rate_allocate_encode(opj_tcd_t *p_tcd, @@ -575,7 +576,8 @@ OPJ_BOOL opj_tcd_rateallocate(opj_tcd_t *tcd, if (cp->m_specific_param.m_enc.m_fixed_quality) { /* fixed_quality */ if (OPJ_IS_CINEMA(cp->rsiz) || OPJ_IS_IMF(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, + p_data_written, maxlen, cstr_info, NULL, tcd->cur_tp_num, tcd->tp_pos, + tcd->cur_pino, THRESH_CALC, p_manager)) { lo = thresh; @@ -605,7 +607,8 @@ OPJ_BOOL opj_tcd_rateallocate(opj_tcd_t *tcd, } } 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, + p_data_written, maxlen, cstr_info, NULL, tcd->cur_tp_num, tcd->tp_pos, + tcd->cur_pino, THRESH_CALC, p_manager)) { /* TODO: what to do with l ??? seek / tell ??? */ /* opj_event_msg(tcd->cinfo, EVT_INFO, "rate alloc: len=%d, max=%d\n", l, maxlen); */ @@ -1370,6 +1373,7 @@ OPJ_BOOL opj_tcd_encode_tile(opj_tcd_t *p_tcd, OPJ_UINT32 * p_data_written, OPJ_UINT32 p_max_length, opj_codestream_info_t *p_cstr_info, + opj_tcd_marker_info_t* p_marker_info, opj_event_mgr_t *p_manager) { @@ -1449,7 +1453,7 @@ OPJ_BOOL opj_tcd_encode_tile(opj_tcd_t *p_tcd, /* FIXME _ProfStart(PGROUP_T2); */ if (! opj_tcd_t2_encode(p_tcd, p_dest, p_data_written, p_max_length, - p_cstr_info, p_manager)) { + p_cstr_info, p_marker_info, p_manager)) { return OPJ_FALSE; } /* FIXME _ProfStop(PGROUP_T2); */ @@ -2541,6 +2545,7 @@ static OPJ_BOOL opj_tcd_t2_encode(opj_tcd_t *p_tcd, OPJ_UINT32 * p_data_written, OPJ_UINT32 p_max_dest_size, opj_codestream_info_t *p_cstr_info, + opj_tcd_marker_info_t* p_marker_info, opj_event_mgr_t *p_manager) { opj_t2_t * l_t2; @@ -2559,6 +2564,7 @@ static OPJ_BOOL opj_tcd_t2_encode(opj_tcd_t *p_tcd, p_data_written, p_max_dest_size, p_cstr_info, + p_marker_info, p_tcd->tp_num, p_tcd->tp_pos, p_tcd->cur_pino, @@ -2819,3 +2825,29 @@ static OPJ_BOOL opj_tcd_is_whole_tilecomp_decoding(opj_tcd_t *p_tcd, (((OPJ_UINT32)tilec->x1 - tcx1) >> shift) == 0 && (((OPJ_UINT32)tilec->y1 - tcy1) >> shift) == 0))); } + +/* ----------------------------------------------------------------------- */ + +opj_tcd_marker_info_t* opj_tcd_marker_info_create(OPJ_BOOL need_PLT) +{ + opj_tcd_marker_info_t *l_tcd_marker_info = + (opj_tcd_marker_info_t*) opj_calloc(1, sizeof(opj_tcd_marker_info_t)); + if (!l_tcd_marker_info) { + return NULL; + } + + l_tcd_marker_info->need_PLT = need_PLT; + + return l_tcd_marker_info; +} + +/* ----------------------------------------------------------------------- */ + +void opj_tcd_marker_info_destroy(opj_tcd_marker_info_t *p_tcd_marker_info) +{ + if (p_tcd_marker_info) { + opj_free(p_tcd_marker_info->p_packet_size); + } +} + +/* ----------------------------------------------------------------------- */ diff --git a/src/lib/openjp2/tcd.h b/src/lib/openjp2/tcd.h index 67739170..f1b52b8d 100644 --- a/src/lib/openjp2/tcd.h +++ b/src/lib/openjp2/tcd.h @@ -284,6 +284,22 @@ typedef struct opj_tcd { OPJ_BOOL* used_component; } opj_tcd_t; +/** + * Structure to hold information needed to generate some markers. + * Used by encoder. + */ +typedef struct opj_tcd_marker_info { + /** In: Whether information to generate PLT markers in needed */ + OPJ_BOOL need_PLT; + + /** OUT: Number of elements in p_packet_size[] array */ + OPJ_UINT32 packet_count; + + /** OUT: Array of size packet_count, such that p_packet_size[i] is + * the size in bytes of the ith packet */ + OPJ_UINT32* p_packet_size; +} opj_tcd_marker_info_t; + /** @name Exported functions */ /*@{*/ /* ----------------------------------------------------------------------- */ @@ -306,6 +322,21 @@ Destroy a previously created TCD handle */ void opj_tcd_destroy(opj_tcd_t *tcd); + +/** + * Create a new opj_tcd_marker_info_t* structure + * @param need_PLT Whether information is needed to generate PLT markers. + */ +opj_tcd_marker_info_t* opj_tcd_marker_info_create(OPJ_BOOL need_PLT); + + +/** +Destroy a previously created opj_tcd_marker_info_t* structure +@param p_tcd_marker_info Structure to destroy +*/ +void opj_tcd_marker_info_destroy(opj_tcd_marker_info_t *p_tcd_marker_info); + + /** * Initialize the tile coder and may reuse some memory. * @param p_tcd TCD handle. @@ -364,6 +395,7 @@ OPJ_UINT32 opj_tcd_get_decoded_tile_size(opj_tcd_t *p_tcd, * @param p_data_written pointer to an int that is incremented by the number of bytes really written on p_dest * @param p_len Maximum length of the destination buffer * @param p_cstr_info Codestream information structure + * @param p_marker_info Marker information structure * @param p_manager the user event manager * @return true if the coding is successful. */ @@ -373,6 +405,7 @@ OPJ_BOOL opj_tcd_encode_tile(opj_tcd_t *p_tcd, OPJ_UINT32 * p_data_written, OPJ_UINT32 p_len, struct opj_codestream_info *p_cstr_info, + opj_tcd_marker_info_t* p_marker_info, opj_event_mgr_t *p_manager); diff --git a/tests/nonregression/test_suite.ctest.in b/tests/nonregression/test_suite.ctest.in index 9d4961af..3ed97ab1 100644 --- a/tests/nonregression/test_suite.ctest.in +++ b/tests/nonregression/test_suite.ctest.in @@ -183,6 +183,9 @@ opj_compress_no_raw_lossless -i @INPUT_NR_PATH@/X_4_2K_24_185_CBR_WB_000.tif -o opj_compress_no_raw_lossless -i @INPUT_NR_PATH@/ElephantDream_4K.tif -o @TEMP_PATH@/X_4_2K_24_185_CBR_WB_000_IMF_4K_R.j2k -IMF 4K_R opj_compress_no_raw_lossless -i @INPUT_NR_PATH@/ElephantDream_4K.tif -o @TEMP_PATH@/X_4_2K_24_185_CBR_WB_000_IMF_8K_R.j2k -IMF 8K_R +opj_compress_no_raw_lossless -i @INPUT_NR_PATH@/byte.tif -o @TEMP_PATH@/byte_PLT.j2k -n 1 -PLT +opj_compress_no_raw_lossless -i @INPUT_NR_PATH@/byte.tif -o @TEMP_PATH@/byte_PLT.jp2 -n 1 -PLT + # DECODER TEST SUITE opj_decompress -i @INPUT_NR_PATH@/Bretagne2.j2k -o @TEMP_PATH@/Bretagne2.j2k.pgx opj_decompress -i @INPUT_NR_PATH@/_00042.j2k -o @TEMP_PATH@/_00042.j2k.pgx