diff options
| author | Even Rouault <even.rouault@spatialys.com> | 2017-09-01 16:30:48 +0200 |
|---|---|---|
| committer | Even Rouault <even.rouault@spatialys.com> | 2017-09-01 16:30:48 +0200 |
| commit | 0ae3cba3404674bbe2028ea9a801301a4c951b33 (patch) | |
| tree | 8150750654ca96ea629ded16cc2731d9e0bd9cdf /src | |
| parent | 5d07d463fdb0a5eeffa90eba1566cc21697011b8 (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.c | 62 | ||||
| -rw-r--r-- | src/lib/openjp2/openjpeg.h | 6 | ||||
| -rw-r--r-- | src/lib/openjp2/t1.c | 42 |
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, |
