summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEven Rouault <even.rouault@spatialys.com>2017-09-01 16:30:48 +0200
committerEven Rouault <even.rouault@spatialys.com>2017-09-01 16:30:48 +0200
commit0ae3cba3404674bbe2028ea9a801301a4c951b33 (patch)
tree8150750654ca96ea629ded16cc2731d9e0bd9cdf /src
parent5d07d463fdb0a5eeffa90eba1566cc21697011b8 (diff)
Allow several repeated calls to opj_set_decode_area() and opj_decode() for single-tiled images
* Only works for single-tiled images --> will error out cleanly, as currently in other cases * Save re-reading the codestream for the tile, and re-use code-blocks of the previous decoding pass. * Future improvements might involve improving opj_decompress, and the image writing logic, to use this strategy.
Diffstat (limited to 'src')
-rw-r--r--src/lib/openjp2/j2k.c62
-rw-r--r--src/lib/openjp2/openjpeg.h6
-rw-r--r--src/lib/openjp2/t1.c42
3 files changed, 89 insertions, 21 deletions
diff --git a/src/lib/openjp2/j2k.c b/src/lib/openjp2/j2k.c
index f1a894a4..e548fefc 100644
--- a/src/lib/openjp2/j2k.c
+++ b/src/lib/openjp2/j2k.c
@@ -9147,10 +9147,15 @@ OPJ_BOOL opj_j2k_set_decode_area(opj_j2k_t *p_j2k,
OPJ_BOOL ret;
OPJ_UINT32 it_comp;
+ if (p_j2k->m_cp.tw == 1 && p_j2k->m_cp.th == 1 &&
+ &p_j2k->m_cp.tcps[0].m_data != NULL) {
+ /* In the case of a single-tiled image whose codestream we have already */
+ /* ingested, go on */
+ }
/* Check if we are read the main header */
- if (p_j2k->m_specific_param.m_decoder.m_state != J2K_STATE_TPHSOT) {
+ else if (p_j2k->m_specific_param.m_decoder.m_state != J2K_STATE_TPHSOT) {
opj_event_msg(p_manager, EVT_ERROR,
- "Need to decode the main header before begin to decode the remaining codestream");
+ "Need to decode the main header before begin to decode the remaining codestream.\n");
return OPJ_FALSE;
}
@@ -10508,20 +10513,27 @@ static OPJ_BOOL opj_j2k_decode_tiles(opj_j2k_t *p_j2k,
}
for (;;) {
- if (! opj_j2k_read_tile_header(p_j2k,
- &l_current_tile_no,
- NULL,
- &l_tile_x0, &l_tile_y0,
- &l_tile_x1, &l_tile_y1,
- &l_nb_comps,
- &l_go_on,
- p_stream,
- p_manager)) {
- return OPJ_FALSE;
- }
+ if (p_j2k->m_cp.tw == 1 && p_j2k->m_cp.th == 1 &&
+ p_j2k->m_cp.tcps[0].m_data != NULL) {
+ l_current_tile_no = 0;
+ p_j2k->m_current_tile_number = 0;
+ p_j2k->m_specific_param.m_decoder.m_state |= J2K_STATE_DATA;
+ } else {
+ if (! opj_j2k_read_tile_header(p_j2k,
+ &l_current_tile_no,
+ NULL,
+ &l_tile_x0, &l_tile_y0,
+ &l_tile_x1, &l_tile_y1,
+ &l_nb_comps,
+ &l_go_on,
+ p_stream,
+ p_manager)) {
+ return OPJ_FALSE;
+ }
- if (! l_go_on) {
- break;
+ if (! l_go_on) {
+ break;
+ }
}
if (! opj_j2k_decode_tile(p_j2k, l_current_tile_no, NULL, 0,
@@ -10538,7 +10550,16 @@ static OPJ_BOOL opj_j2k_decode_tiles(opj_j2k_t *p_j2k,
p_j2k->m_output_image)) {
return OPJ_FALSE;
}
- opj_j2k_tcp_data_destroy(&p_j2k->m_cp.tcps[l_current_tile_no]);
+
+ if (p_j2k->m_cp.tw == 1 && p_j2k->m_cp.th == 1 &&
+ !(p_j2k->m_output_image->x0 == p_j2k->m_private_image->x0 &&
+ p_j2k->m_output_image->y0 == p_j2k->m_private_image->y0 &&
+ p_j2k->m_output_image->x1 == p_j2k->m_private_image->x1 &&
+ p_j2k->m_output_image->y1 == p_j2k->m_private_image->y1)) {
+ /* Keep current tcp data */
+ } else {
+ opj_j2k_tcp_data_destroy(&p_j2k->m_cp.tcps[l_current_tile_no]);
+ }
opj_event_msg(p_manager, EVT_INFO,
"Image data has been updated with tile %d.\n\n", l_current_tile_no + 1);
@@ -10738,9 +10759,11 @@ OPJ_BOOL opj_j2k_decode(opj_j2k_t * p_j2k,
}
}
- p_j2k->m_output_image = opj_image_create0();
- if (!(p_j2k->m_output_image)) {
- return OPJ_FALSE;
+ if (p_j2k->m_output_image == NULL) {
+ p_j2k->m_output_image = opj_image_create0();
+ if (!(p_j2k->m_output_image)) {
+ return OPJ_FALSE;
+ }
}
opj_copy_image_header(p_image, p_j2k->m_output_image);
@@ -10760,6 +10783,7 @@ OPJ_BOOL opj_j2k_decode(opj_j2k_t * p_j2k,
for (compno = 0; compno < p_image->numcomps; compno++) {
p_image->comps[compno].resno_decoded =
p_j2k->m_output_image->comps[compno].resno_decoded;
+ opj_image_data_free(p_image->comps[compno].data);
p_image->comps[compno].data = p_j2k->m_output_image->comps[compno].data;
#if 0
char fn[256];
diff --git a/src/lib/openjp2/openjpeg.h b/src/lib/openjp2/openjpeg.h
index 21755b48..7020d37d 100644
--- a/src/lib/openjp2/openjpeg.h
+++ b/src/lib/openjp2/openjpeg.h
@@ -1340,6 +1340,12 @@ OPJ_API OPJ_BOOL OPJ_CALLCONV opj_read_header(opj_stream_t *p_stream,
* that is to say at the highest resolution level, even if requesting the image at lower
* resolution levels.
*
+ * Generally opj_set_decode_area() should be followed by opj_decode(), and the
+ * codec cannot be re-used.
+ * In the particular case of an image made of a single tile, several sequences of
+ * calls to opoj_set_decode_area() and opj_decode() are allowed, and will bring
+ * performance improvements when reading an image by chunks.
+ *
* @param p_codec the jpeg2000 codec.
* @param p_image the decoded image previously setted by opj_read_header
* @param p_start_x the left position of the rectangle to decode (in image coordinates).
diff --git a/src/lib/openjp2/t1.c b/src/lib/openjp2/t1.c
index 44a2f243..0277f8cc 100644
--- a/src/lib/openjp2/t1.c
+++ b/src/lib/openjp2/t1.c
@@ -1668,6 +1668,11 @@ static void opj_t1_clbl_decode_processor(void* user_data, opj_tls_t* tls)
}
}
+ /* Both can be non NULL if for example decoding a full tile and then */
+ /* partially a tile. In which case partial decoding should be the */
+ /* priority */
+ assert((cblk->decoded_data != NULL) || (tilec->data != NULL));
+
if (cblk->decoded_data) {
if (tccp->qmfbid == 1) {
for (j = 0; j < cblk_h; ++j) {
@@ -1763,6 +1768,17 @@ void opj_t1_decode_cblks(opj_tcd_t* tcd,
(OPJ_UINT32)precinct->y0,
(OPJ_UINT32)precinct->x1,
(OPJ_UINT32)precinct->y1)) {
+ for (cblkno = 0; cblkno < precinct->cw * precinct->ch; ++cblkno) {
+ opj_tcd_cblk_dec_t* cblk = &precinct->cblks.dec[cblkno];
+ if (cblk->decoded_data) {
+#ifdef DEBUG_VERBOSE
+ printf("Discarding codeblock %d,%d at resno=%d, bandno=%d\n",
+ cblk->x0, cblk->y0, resno, bandno);
+#endif
+ opj_free(cblk->decoded_data);
+ cblk->decoded_data = NULL;
+ }
+ }
continue;
}
@@ -1770,8 +1786,6 @@ void opj_t1_decode_cblks(opj_tcd_t* tcd,
opj_tcd_cblk_dec_t* cblk = &precinct->cblks.dec[cblkno];
opj_t1_cblk_decode_processing_job_t* job;
- assert(cblk->decoded_data == NULL);
-
if (!opj_tcd_is_subband_area_of_interest(tcd,
tilec->compno,
resno,
@@ -1780,15 +1794,34 @@ void opj_t1_decode_cblks(opj_tcd_t* tcd,
(OPJ_UINT32)cblk->y0,
(OPJ_UINT32)cblk->x1,
(OPJ_UINT32)cblk->y1)) {
+ if (cblk->decoded_data) {
+#ifdef DEBUG_VERBOSE
+ printf("Discarding codeblock %d,%d at resno=%d, bandno=%d\n",
+ cblk->x0, cblk->y0, resno, bandno);
+#endif
+ opj_free(cblk->decoded_data);
+ cblk->decoded_data = NULL;
+ }
continue;
}
if (!tcd->whole_tile_decoding) {
OPJ_UINT32 cblk_w = (OPJ_UINT32)(cblk->x1 - cblk->x0);
OPJ_UINT32 cblk_h = (OPJ_UINT32)(cblk->y1 - cblk->y0);
+ if (cblk->decoded_data != NULL) {
+#ifdef DEBUG_VERBOSE
+ printf("Reusing codeblock %d,%d at resno=%d, bandno=%d\n",
+ cblk->x0, cblk->y0, resno, bandno);
+#endif
+ continue;
+ }
if (cblk_w == 0 || cblk_h == 0) {
continue;
}
+#ifdef DEBUG_VERBOSE
+ printf("Decoding codeblock %d,%d at resno=%d, bandno=%d\n",
+ cblk->x0, cblk->y0, resno, bandno);
+#endif
/* Zero-init required */
cblk->decoded_data = opj_calloc(1, cblk_w * cblk_h * sizeof(OPJ_INT32));
if (cblk->decoded_data == NULL) {
@@ -1803,6 +1836,11 @@ void opj_t1_decode_cblks(opj_tcd_t* tcd,
*pret = OPJ_FALSE;
return;
}
+ } else if (cblk->decoded_data) {
+ /* Not sure if that code path can happen, but better be */
+ /* safe than sorry */
+ opj_free(cblk->decoded_data);
+ cblk->decoded_data = NULL;
}
job = (opj_t1_cblk_decode_processing_job_t*) opj_calloc(1,