Skip to content

Commit

Permalink
Merge pull request #1246 from rouault/write_plt
Browse files Browse the repository at this point in the history
Add support for generation of PLT markers in encoder
  • Loading branch information
rouault authored May 20, 2020
2 parents 64689d0 + 4edb8c8 commit 1d358f2
Show file tree
Hide file tree
Showing 15 changed files with 468 additions and 13 deletions.
30 changes: 27 additions & 3 deletions src/bin/jp2/opj_compress.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 <key value>\n");
fprintf(stdout, " Mode switch.\n");
fprintf(stdout, " [1=BYPASS(LAZY) 2=RESET 4=RESTART(TERMALL)\n");
Expand Down Expand Up @@ -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;
Expand All @@ -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 */
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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(&parameters);

Expand All @@ -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, &parameters, &img_fol, &raw_cp,
indexfilename, sizeof(indexfilename), &framerate) == 1) {
indexfilename, sizeof(indexfilename), &framerate, &PLT) == 1) {
ret = 1;
goto fin;
}
Expand Down Expand Up @@ -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) {
Expand Down
200 changes: 198 additions & 2 deletions src/lib/openjp2/j2k.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand All @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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)
Expand Down
19 changes: 19 additions & 0 deletions src/lib/openjp2/j2k.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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.
Expand Down
12 changes: 12 additions & 0 deletions src/lib/openjp2/jp2.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading

0 comments on commit 1d358f2

Please sign in to comment.