Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for generation of PLT markers in encoder #1246

Merged
merged 1 commit into from
May 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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