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

added support for partial bitstream decoding #1251

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
19 changes: 16 additions & 3 deletions src/lib/openjp2/j2k.c
Original file line number Diff line number Diff line change
Expand Up @@ -4964,9 +4964,14 @@ static OPJ_BOOL opj_j2k_read_sod(opj_j2k_t *p_j2k,
/* 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(p_j2k->m_cp.strict) {
opj_event_msg(p_manager, EVT_ERROR,
"Tile part length size inconsistent with stream length\n");
return OPJ_FALSE;
} else {
opj_event_msg(p_manager, EVT_WARNING,
"Tile part length size inconsistent with stream length\n");
}
}
if (p_j2k->m_specific_param.m_decoder.m_sot_length >
UINT_MAX - OPJ_COMMON_CBLK_DATA_EXTRA) {
Expand Down Expand Up @@ -6685,6 +6690,7 @@ void opj_j2k_setup_decoder(opj_j2k_t *j2k, opj_dparameters_t *parameters)
if (j2k && parameters) {
j2k->m_cp.m_specific_param.m_dec.m_layer = parameters->cp_layer;
j2k->m_cp.m_specific_param.m_dec.m_reduce = parameters->cp_reduce;
j2k->m_cp.strict = OPJ_TRUE;

j2k->dump_state = (parameters->flags & OPJ_DPARAMETERS_DUMP_FLAG);
#ifdef USE_JPWL
Expand All @@ -6695,6 +6701,13 @@ void opj_j2k_setup_decoder(opj_j2k_t *j2k, opj_dparameters_t *parameters)
}
}

void opj_j2k_decoder_set_strict_mode(opj_j2k_t *j2k, OPJ_BOOL strict)
{
if (j2k) {
j2k->m_cp.strict = strict;
}
}

OPJ_BOOL opj_j2k_set_threads(opj_j2k_t *j2k, OPJ_UINT32 num_threads)
{
/* Currently we pass the thread-pool to the tcd, so we cannot re-set it */
Expand Down
4 changes: 4 additions & 0 deletions src/lib/openjp2/j2k.h
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,8 @@ typedef struct opj_cp {
}
m_specific_param;

/** OPJ_TRUE if entire bit stream must be decoded, OPJ_FALSE if partial bitstream decoding allowed */
OPJ_BOOL strict;

/* UniPG>> */
#ifdef USE_JPWL
Expand Down Expand Up @@ -622,6 +624,8 @@ Decoding parameters are returned in j2k->cp.
*/
void opj_j2k_setup_decoder(opj_j2k_t *j2k, opj_dparameters_t *parameters);

void opj_j2k_decoder_set_strict_mode(opj_j2k_t *j2k, OPJ_BOOL strict);

OPJ_BOOL opj_j2k_set_threads(opj_j2k_t *j2k, OPJ_UINT32 num_threads);

/**
Expand Down
5 changes: 5 additions & 0 deletions src/lib/openjp2/jp2.c
Original file line number Diff line number Diff line change
Expand Up @@ -1901,6 +1901,11 @@ void opj_jp2_setup_decoder(opj_jp2_t *jp2, opj_dparameters_t *parameters)
OPJ_DPARAMETERS_IGNORE_PCLR_CMAP_CDEF_FLAG;
}

void opj_jp2_decoder_set_strict_mode(opj_jp2_t *jp2, OPJ_BOOL strict)
{
opj_j2k_decoder_set_strict_mode(jp2->j2k, strict);
}

OPJ_BOOL opj_jp2_set_threads(opj_jp2_t *jp2, OPJ_UINT32 num_threads)
{
return opj_j2k_set_threads(jp2->j2k, num_threads);
Expand Down
9 changes: 9 additions & 0 deletions src/lib/openjp2/jp2.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,15 @@ Decoding parameters are returned in jp2->j2k->cp.
*/
void opj_jp2_setup_decoder(opj_jp2_t *jp2, opj_dparameters_t *parameters);

/**
Set the strict mode parameter. When strict mode is enabled, the entire
bitstream must be decoded or an error is returned. When it is disabled,
the decoder will decode partial bitstreams.
@param jp2 JP2 decompressor handle
@param strict JPH_TRUE for strict mode
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@param strict JPH_TRUE for strict mode
@param strict OPJ_TRUE for strict mode

*/
void opj_jp2_decoder_set_strict_mode(opj_jp2_t *jp2, OPJ_BOOL strict);

/** Allocates worker threads for the compressor/decompressor.
*
* @param jp2 JP2 decompressor handle
Expand Down
27 changes: 27 additions & 0 deletions src/lib/openjp2/openjpeg.c
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,10 @@ opj_codec_t* OPJ_CALLCONV opj_create_decompress(OPJ_CODEC_FORMAT p_format)
l_codec->m_codec_data.m_decompression.opj_setup_decoder =
(void (*)(void *, opj_dparameters_t *)) opj_j2k_setup_decoder;

l_codec->m_codec_data.m_decompression.opj_decoder_set_strict_mode =
(void (*)(void *, OPJ_BOOL)) opj_j2k_decoder_set_strict_mode;


l_codec->m_codec_data.m_decompression.opj_read_tile_header =
(OPJ_BOOL(*)(void *,
OPJ_UINT32*,
Expand Down Expand Up @@ -326,6 +330,9 @@ opj_codec_t* OPJ_CALLCONV opj_create_decompress(OPJ_CODEC_FORMAT p_format)
l_codec->m_codec_data.m_decompression.opj_setup_decoder =
(void (*)(void *, opj_dparameters_t *)) opj_jp2_setup_decoder;

l_codec->m_codec_data.m_decompression.opj_decoder_set_strict_mode =
(void (*)(void *, OPJ_BOOL)) opj_jp2_decoder_set_strict_mode;

l_codec->m_codec_data.m_decompression.opj_set_decode_area =
(OPJ_BOOL(*)(void *,
opj_image_t*,
Expand Down Expand Up @@ -426,6 +433,26 @@ OPJ_BOOL OPJ_CALLCONV opj_setup_decoder(opj_codec_t *p_codec,
return OPJ_FALSE;
}

OPJ_API OPJ_BOOL OPJ_CALLCONV opj_decoder_set_strict_mode(opj_codec_t *p_codec, OPJ_BOOL strict)
{
if (p_codec) {
opj_codec_private_t * l_codec = (opj_codec_private_t *) p_codec;

if (! l_codec->is_decompressor) {
opj_event_msg(&(l_codec->m_event_mgr), EVT_ERROR,
"Codec provided to the opj_decoder_set_strict_mode function is not a decompressor handler.\n");
return OPJ_FALSE;
}

l_codec->m_codec_data.m_decompression.opj_decoder_set_strict_mode(l_codec->m_codec,
strict);
return OPJ_TRUE;
}
return OPJ_FALSE;

}


OPJ_BOOL OPJ_CALLCONV opj_read_header(opj_stream_t *p_stream,
opj_codec_t *p_codec,
opj_image_t **p_image)
Expand Down
13 changes: 13 additions & 0 deletions src/lib/openjp2/openjpeg.h
Original file line number Diff line number Diff line change
Expand Up @@ -1339,6 +1339,19 @@ OPJ_API void OPJ_CALLCONV opj_set_default_decoder_parameters(
OPJ_API OPJ_BOOL OPJ_CALLCONV opj_setup_decoder(opj_codec_t *p_codec,
opj_dparameters_t *parameters);

/**
* Set strict decoding parameter for this decoder. If strict decoding is enabled, partial bit
* streams will fail to decode. If strict decoding is disabled, the decoder will decode partial
* bitstreams as much as possible without erroring
*
* @param p_codec decompressor handler
* @param strict OBJ_TRUE to enable strict decoding, OBJ_FALSE to disable
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @param strict OBJ_TRUE to enable strict decoding, OBJ_FALSE to disable
* @param strict OPJ_TRUE to enable strict decoding, OPJ_FALSE to disable

*
* @return true if the decoder is correctly set
*/

OPJ_API OPJ_BOOL OPJ_CALLCONV opj_decoder_set_strict_mode(opj_codec_t *p_codec, OPJ_BOOL strict);

/**
* Allocates worker threads for the compressor/decompressor.
*
Expand Down
3 changes: 3 additions & 0 deletions src/lib/openjp2/opj_codec.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ typedef struct opj_codec_private {
/** Setup decoder function handler */
void (*opj_setup_decoder)(void * p_codec, opj_dparameters_t * p_param);

/** Strict mode function handler */
void (*opj_decoder_set_strict_mode)(void * p_codec, OPJ_BOOL strict);

/** Set decode area function handler */
OPJ_BOOL(*opj_set_decode_area)(void * p_codec,
opj_image_t * p_image,
Expand Down
67 changes: 53 additions & 14 deletions src/lib/openjp2/t2.c
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,6 @@ OPJ_BOOL opj_t2_decode_packets(opj_tcd_t* tcd,
l_current_pi->precno, l_current_pi->layno, skip_packet ? "skipped" : "kept");
*/
}

if (!skip_packet) {
l_nb_bytes_read = 0;

Expand Down Expand Up @@ -1378,6 +1377,7 @@ static OPJ_BOOL opj_t2_read_packet_data(opj_t2_t* p_t2,
opj_tcd_cblk_dec_t* l_cblk = 00;
opj_tcd_resolution_t* l_res =
&p_tile->comps[p_pi->compno].resolutions[p_pi->resno];
OPJ_BOOL partial_buffer = OPJ_FALSE;

OPJ_ARG_NOT_USED(p_t2);
OPJ_ARG_NOT_USED(pack_info);
Expand All @@ -1397,6 +1397,12 @@ static OPJ_BOOL opj_t2_read_packet_data(opj_t2_t* p_t2,
for (cblkno = 0; cblkno < l_nb_code_blocks; ++cblkno) {
opj_tcd_seg_t *l_seg = 00;

// if we have a partial data stream, set numchunks to zero
// since we have no data to actually decode.
if(partial_buffer) {
l_cblk->numchunks = 0;
}

if (!l_cblk->numnewpasses) {
/* nothing to do */
++l_cblk;
Expand All @@ -1419,12 +1425,34 @@ static OPJ_BOOL opj_t2_read_packet_data(opj_t2_t* p_t2,
/* Check possible overflow (on l_current_data only, assumes input args already checked) then size */
if ((((OPJ_SIZE_T)l_current_data + (OPJ_SIZE_T)l_seg->newlen) <
(OPJ_SIZE_T)l_current_data) ||
(l_current_data + l_seg->newlen > p_src_data + p_max_length)) {
opj_event_msg(p_manager, EVT_ERROR,
"read: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n",
l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno,
p_pi->compno);
return OPJ_FALSE;
(l_current_data + l_seg->newlen > p_src_data + p_max_length) ||
(partial_buffer)) {
if(p_t2->cp->strict) {
opj_event_msg(p_manager, EVT_WARNING,
"read: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n",
l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno,
p_pi->compno);
return OPJ_FALSE;
} else {
opj_event_msg(p_manager, EVT_WARNING,
"read: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n",
l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno,
p_pi->compno);
// skip this codeblock since it is a partial read
partial_buffer = OPJ_TRUE;
l_cblk->numchunks = 0;

l_seg->numpasses += l_seg->numnewpasses;
l_cblk->numnewpasses -= l_seg->numnewpasses;
if (l_cblk->numnewpasses > 0) {
++l_seg;
++l_cblk->numsegs;
}
if(l_cblk->numnewpasses > 0) {
break;
}
continue;
}
}

#ifdef USE_JPWL
Expand Down Expand Up @@ -1486,8 +1514,12 @@ static OPJ_BOOL opj_t2_read_packet_data(opj_t2_t* p_t2,
++l_band;
}

*(p_data_read) = (OPJ_UINT32)(l_current_data - p_src_data);

// return the number of bytes read
if(partial_buffer) {
*(p_data_read) = p_max_length;
} else {
*(p_data_read) = (OPJ_UINT32)(l_current_data - p_src_data);
}

return OPJ_TRUE;
}
Expand Down Expand Up @@ -1549,11 +1581,18 @@ static OPJ_BOOL opj_t2_skip_packet_data(opj_t2_t* p_t2,
/* Check possible overflow then size */
if (((*p_data_read + l_seg->newlen) < (*p_data_read)) ||
((*p_data_read + l_seg->newlen) > p_max_length)) {
opj_event_msg(p_manager, EVT_ERROR,
"skip: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n",
l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno,
p_pi->compno);
return OPJ_FALSE;
if(p_t2->cp->strict) {
opj_event_msg(p_manager, EVT_ERROR,
"skip: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n",
l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno,
p_pi->compno);
return OPJ_FALSE;
} else {
opj_event_msg(p_manager, EVT_WARNING,
"skip: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n",
l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno,
p_pi->compno);
}
}

#ifdef USE_JPWL
Expand Down