/**
* 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
opj_read_bytes(p_header_data, &l_tcp->mct, 1); /* SGcod (C) */
++p_header_data;
+ if (l_tcp->mct > 1) {
+ opj_event_msg(p_manager, EVT_ERROR,
+ "Invalid multiple component transformation\n");
+ return OPJ_FALSE;
+ }
+
p_header_size -= 5;
for (i = 0; i < l_image->numcomps; ++i) {
l_tcp->tccps[i].csty = l_tcp->csty & J2K_CCP_CSTY_PRT;
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;
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,
{
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);
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;
*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;
}
OPJ_FLOAT32 * l_rates = 0;
OPJ_FLOAT32 l_sot_remove;
OPJ_UINT32 l_bits_empty, l_size_pixel;
- OPJ_UINT32 l_tile_size = 0;
+ OPJ_UINT64 l_tile_size = 0;
OPJ_UINT32 l_last_res;
OPJ_FLOAT32(* l_tp_stride_func)(opj_tcp_t *) = 00;
l_rates = l_tcp->rates;
/* Modification of the RATE >> */
- if (*l_rates > 0.0f) {
- *l_rates = (((OPJ_FLOAT32)(l_size_pixel * (OPJ_UINT32)(l_x1 - l_x0) *
- (OPJ_UINT32)(l_y1 - l_y0)))
- /
- ((*l_rates) * (OPJ_FLOAT32)l_bits_empty)
- )
- -
- l_offset;
- }
-
- ++l_rates;
-
- for (k = 1; k < l_tcp->numlayers; ++k) {
+ for (k = 0; k < l_tcp->numlayers; ++k) {
if (*l_rates > 0.0f) {
- *l_rates = (((OPJ_FLOAT32)(l_size_pixel * (OPJ_UINT32)(l_x1 - l_x0) *
- (OPJ_UINT32)(l_y1 - l_y0)))
- /
- ((*l_rates) * (OPJ_FLOAT32)l_bits_empty)
- )
+ *l_rates = (OPJ_FLOAT32)(((OPJ_FLOAT64)l_size_pixel * (OPJ_UINT32)(
+ l_x1 - l_x0) *
+ (OPJ_UINT32)(l_y1 - l_y0))
+ / ((*l_rates) * (OPJ_FLOAT32)l_bits_empty))
-
l_offset;
}
l_tile_size = 0;
for (i = 0; i < l_image->numcomps; ++i) {
- l_tile_size += (opj_uint_ceildiv(l_cp->tdx, l_img_comp->dx)
- *
- opj_uint_ceildiv(l_cp->tdy, l_img_comp->dy)
- *
- l_img_comp->prec
- );
+ l_tile_size += (OPJ_UINT64)opj_uint_ceildiv(l_cp->tdx, l_img_comp->dx)
+ *
+ opj_uint_ceildiv(l_cp->tdy, l_img_comp->dy)
+ *
+ l_img_comp->prec;
++l_img_comp;
}
/* bin/test_tile_encoder 1 256 256 32 32 8 0 reversible_with_precinct.j2k 4 4 3 0 0 1 16 16 */
/* TODO revise this to take into account the overhead linked to the */
/* number of packets and number of code blocks in packets */
- l_tile_size = (OPJ_UINT32)(l_tile_size * 1.4 / 8);
+ l_tile_size = (OPJ_UINT64)((double)l_tile_size * 1.4 / 8);
/* Arbitrary amount to make the following work: */
/* bin/test_tile_encoder 1 256 256 17 16 8 0 reversible_no_precinct.j2k 4 4 3 0 0 1 */
l_tile_size += opj_j2k_get_specific_header_sizes(p_j2k);
- p_j2k->m_specific_param.m_encoder.m_encoded_tile_size = l_tile_size;
+ if (l_tile_size > UINT_MAX) {
+ l_tile_size = UINT_MAX;
+ }
+
+ p_j2k->m_specific_param.m_encoder.m_encoded_tile_size = (OPJ_UINT32)l_tile_size;
p_j2k->m_specific_param.m_encoder.m_encoded_tile_data =
(OPJ_BYTE *) opj_malloc(p_j2k->m_specific_param.m_encoder.m_encoded_tile_size);
if (p_j2k->m_specific_param.m_encoder.m_encoded_tile_data == 00) {
+ opj_event_msg(p_manager, EVT_ERROR,
+ "Not enough memory to allocate m_encoded_tile_data. %u MB required\n",
+ (OPJ_UINT32)(l_tile_size / 1024 / 1024));
return OPJ_FALSE;
}
*/
if (parameters->tile_size_on) {
+ if (cp->tdx == 0) {
+ opj_event_msg(p_manager, EVT_ERROR, "Invalid tile width\n");
+ return OPJ_FALSE;
+ }
+ if (cp->tdy == 0) {
+ opj_event_msg(p_manager, EVT_ERROR, "Invalid tile height\n");
+ return OPJ_FALSE;
+ }
cp->tw = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)(image->x1 - cp->tx0),
(OPJ_INT32)cp->tdx);
cp->th = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)(image->y1 - cp->ty0),
if (tileno + 1 == parameters->POC[i].tile) {
opj_poc_t *tcp_poc = &tcp->pocs[numpocs_tile];
+ if (parameters->POC[numpocs_tile].compno0 >= image->numcomps) {
+ opj_event_msg(p_manager, EVT_ERROR,
+ "Invalid compno0 for POC %d\n", i);
+ return OPJ_FALSE;
+ }
+
tcp_poc->resno0 = parameters->POC[numpocs_tile].resno0;
tcp_poc->compno0 = parameters->POC[numpocs_tile].compno0;
tcp_poc->layno1 = parameters->POC[numpocs_tile].layno1;
tcp_poc->resno1 = parameters->POC[numpocs_tile].resno1;
- tcp_poc->compno1 = parameters->POC[numpocs_tile].compno1;
+ tcp_poc->compno1 = opj_uint_min(parameters->POC[numpocs_tile].compno1,
+ image->numcomps);
tcp_poc->prg1 = parameters->POC[numpocs_tile].prg1;
tcp_poc->tile = parameters->POC[numpocs_tile].tile;
/*Allocate and initialize some elements of codestrem index*/
if (!opj_j2k_allocate_tile_element_cstr_index(p_j2k)) {
+ opj_image_destroy(*p_image);
+ *p_image = NULL;
return OPJ_FALSE;
}
OPJ_UINT32 l_marker_size;
const opj_dec_memory_marker_handler_t * l_marker_handler = 00;
opj_tcp_t * l_tcp = NULL;
+ const OPJ_UINT32 l_nb_tiles = p_j2k->m_cp.tw * p_j2k->m_cp.th;
/* preconditions */
assert(p_stream != 00);
return OPJ_FALSE;
}
if (l_correction_needed) {
- OPJ_UINT32 l_nb_tiles = p_j2k->m_cp.tw * p_j2k->m_cp.th;
OPJ_UINT32 l_tile_no;
p_j2k->m_specific_param.m_decoder.m_can_decode = 0;
"Non conformant codestream TPsot==TNsot.\n");
}
}
- if (! p_j2k->m_specific_param.m_decoder.m_can_decode) {
- /* Try to read 2 bytes (the next marker ID) from stream and copy them into the buffer */
- if (opj_stream_read_data(p_stream,
- p_j2k->m_specific_param.m_decoder.m_header_data, 2, p_manager) != 2) {
- opj_event_msg(p_manager, EVT_ERROR, "Stream too short\n");
- return OPJ_FALSE;
- }
-
- /* Read 2 bytes from buffer as the new marker ID */
- opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data,
- &l_current_marker, 2);
- }
} else {
/* Indicate we will try to read a new tile-part header*/
p_j2k->m_specific_param.m_decoder.m_skip_data = 0;
p_j2k->m_specific_param.m_decoder.m_can_decode = 0;
p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_TPHSOT;
+ }
+ if (! p_j2k->m_specific_param.m_decoder.m_can_decode) {
/* Try to read 2 bytes (the next marker ID) from stream and copy them into the buffer */
if (opj_stream_read_data(p_stream,
p_j2k->m_specific_param.m_decoder.m_header_data, 2, p_manager) != 2) {
+
+ /* Deal with likely non conformant SPOT6 files, where the last */
+ /* row of tiles have TPsot == 0 and TNsot == 0, and missing EOC, */
+ /* but no other tile-parts were found. */
+ if (p_j2k->m_current_tile_number + 1 == l_nb_tiles) {
+ OPJ_UINT32 l_tile_no;
+ for (l_tile_no = 0U; l_tile_no < l_nb_tiles; ++l_tile_no) {
+ if (p_j2k->m_cp.tcps[l_tile_no].m_current_tile_part_number == 0 &&
+ p_j2k->m_cp.tcps[l_tile_no].m_nb_tile_parts == 0) {
+ break;
+ }
+ }
+ if (l_tile_no < l_nb_tiles) {
+ opj_event_msg(p_manager, EVT_INFO,
+ "Tile %u has TPsot == 0 and TNsot == 0, "
+ "but no other tile-parts were found. "
+ "EOC is also missing.\n",
+ l_tile_no);
+ p_j2k->m_current_tile_number = l_tile_no;
+ l_current_marker = J2K_MS_EOC;
+ p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_EOC;
+ break;
+ }
+ }
+
opj_event_msg(p_manager, EVT_ERROR, "Stream too short\n");
return OPJ_FALSE;
}
}
}
- /* FIXME DOC ???*/
+ /* Deal with tiles that have a single tile-part with TPsot == 0 and TNsot == 0 */
if (! p_j2k->m_specific_param.m_decoder.m_can_decode) {
- OPJ_UINT32 l_nb_tiles = p_j2k->m_cp.th * p_j2k->m_cp.tw;
l_tcp = p_j2k->m_cp.tcps + p_j2k->m_current_tile_number;
while ((p_j2k->m_current_tile_number < l_nb_tiles) && (l_tcp->m_data == 00)) {
return OPJ_FALSE;
}
- opj_read_bytes(l_current_ptr, &l_tccp->numresolutions,
- 1); /* SPcox (D) */
- ++l_tccp->numresolutions; /* tccp->numresolutions = read() + 1 */
+ /* SPcod (D) / SPcoc (A) */
+ opj_read_bytes(l_current_ptr, &l_tccp->numresolutions, 1);
+ ++l_tccp->numresolutions; /* tccp->numresolutions = read() + 1 */
if (l_tccp->numresolutions > OPJ_J2K_MAXRLVLS) {
opj_event_msg(p_manager, EVT_ERROR,
"Invalid value for numresolutions : %d, max value is set in openjpeg.h at %d\n",
return OPJ_FALSE;
}
- opj_read_bytes(l_current_ptr, &l_tccp->cblkw, 1); /* SPcoc (E) */
+ /* SPcod (E) / SPcoc (B) */
+ opj_read_bytes(l_current_ptr, &l_tccp->cblkw, 1);
++l_current_ptr;
l_tccp->cblkw += 2;
- opj_read_bytes(l_current_ptr, &l_tccp->cblkh, 1); /* SPcoc (F) */
+ /* SPcod (F) / SPcoc (C) */
+ opj_read_bytes(l_current_ptr, &l_tccp->cblkh, 1);
++l_current_ptr;
l_tccp->cblkh += 2;
return OPJ_FALSE;
}
-
- opj_read_bytes(l_current_ptr, &l_tccp->cblksty, 1); /* SPcoc (G) */
+ /* SPcod (G) / SPcoc (D) */
+ opj_read_bytes(l_current_ptr, &l_tccp->cblksty, 1);
++l_current_ptr;
if (l_tccp->cblksty & 0xC0U) { /* 2 msb are reserved, assume we can't read */
opj_event_msg(p_manager, EVT_ERROR,
return OPJ_FALSE;
}
- opj_read_bytes(l_current_ptr, &l_tccp->qmfbid, 1); /* SPcoc (H) */
+ /* SPcod (H) / SPcoc (E) */
+ opj_read_bytes(l_current_ptr, &l_tccp->qmfbid, 1);
++l_current_ptr;
+ if (l_tccp->qmfbid > 1) {
+ opj_event_msg(p_manager, EVT_ERROR,
+ "Error reading SPCod SPCoc element, Invalid transformation found\n");
+ return OPJ_FALSE;
+ }
+
*p_header_size = *p_header_size - 5;
/* use custom precinct size ? */
return OPJ_FALSE;
}
+ /* SPcod (I_i) / SPcoc (F_i) */
for (i = 0; i < l_tccp->numresolutions; ++i) {
- opj_read_bytes(l_current_ptr, &l_tmp, 1); /* SPcoc (I_i) */
+ opj_read_bytes(l_current_ptr, &l_tmp, 1);
++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))) {
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)