Instead of being the full tile size.
* Use a sparse array mechanism to store code-blocks and intermediate stages of
IDWT.
* IDWT, DC level shift and MCT stages are done just on that smaller array.
* Improve copy of tile component array to final image, by saving an intermediate
buffer.
* For full-tile decoding at reduced resolution, only allocate the tile buffer to
the reduced size, instead of the full-resolution size.
endif()
add_subdirectory(src/lib)
option(BUILD_LUTS_GENERATOR "Build utility to generate t1_luts.h" OFF)
-option(BUILD_BENCH_DWT "Build bench_dwt utility (development benchmark)" OFF)
+option(BUILD_UNIT_TESTS "Build unit tests (bench_dwt, test_sparse_array, etc..)" OFF)
#-----------------------------------------------------------------------------
# Build Applications
${CMAKE_CURRENT_SOURCE_DIR}/opj_malloc.c
${CMAKE_CURRENT_SOURCE_DIR}/opj_malloc.h
${CMAKE_CURRENT_SOURCE_DIR}/opj_stdint.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/sparse_array.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/sparse_array.h
)
if(BUILD_JPIP)
add_definitions(-DUSE_JPIP)
TARGET_LINK_LIBRARIES(${OPENJPEG_LIBRARY_NAME} ${CMAKE_THREAD_LIBS_INIT})
endif(OPJ_USE_THREAD AND Threads_FOUND AND CMAKE_USE_PTHREADS_INIT)
-if(BUILD_BENCH_DWT)
- add_executable(bench_dwt bench_dwt.c dwt.c opj_malloc.c thread.c)
+if(BUILD_UNIT_TESTS)
+ add_executable(bench_dwt bench_dwt.c)
if(UNIX)
- target_link_libraries(bench_dwt m)
+ target_link_libraries(bench_dwt m ${OPENJPEG_LIBRARY_NAME})
endif()
if(OPJ_USE_THREAD AND Threads_FOUND AND CMAKE_USE_PTHREADS_INIT)
target_link_libraries(bench_dwt ${CMAKE_THREAD_LIBS_INIT})
endif(OPJ_USE_THREAD AND Threads_FOUND AND CMAKE_USE_PTHREADS_INIT)
-endif(BUILD_BENCH_DWT)
+
+ add_executable(test_sparse_array test_sparse_array.c)
+ if(UNIX)
+ target_link_libraries(test_sparse_array m ${OPENJPEG_LIBRARY_NAME})
+ endif()
+ if(OPJ_USE_THREAD AND Threads_FOUND AND CMAKE_USE_PTHREADS_INIT)
+ target_link_libraries(test_sparse_array ${CMAKE_THREAD_LIBS_INIT})
+ endif(OPJ_USE_THREAD AND Threads_FOUND AND CMAKE_USE_PTHREADS_INIT)
+endif(BUILD_UNIT_TESTS)
memset(&tcd, 0, sizeof(tcd));
tcd.thread_pool = tp;
- tcd.decoded_x0 = (OPJ_UINT32)tilec.x0;
- tcd.decoded_y0 = (OPJ_UINT32)tilec.y0;
- tcd.decoded_x1 = (OPJ_UINT32)tilec.x1;
- tcd.decoded_y1 = (OPJ_UINT32)tilec.y1;
+ tcd.whole_tile_decoding = OPJ_TRUE;
+ tcd.win_x0 = (OPJ_UINT32)tilec.x0;
+ tcd.win_y0 = (OPJ_UINT32)tilec.y0;
+ tcd.win_x1 = (OPJ_UINT32)tilec.x1;
+ tcd.win_y1 = (OPJ_UINT32)tilec.y1;
tcd.tcd_image = &tcd_image;
memset(&tcd_image, 0, sizeof(tcd_image));
tcd_image.tiles = &tcd_tile;
static OPJ_BOOL opj_dwt_decode_tile(opj_thread_pool_t* tp,
opj_tcd_tilecomp_t* tilec, OPJ_UINT32 i);
-static OPJ_BOOL opj_dwt_decode_partial_tile(opj_tcd_t *p_tcd,
- opj_tcd_tilecomp_t* tilec,
- OPJ_UINT32 numres);
+static OPJ_BOOL opj_dwt_decode_partial_tile(
+ opj_tcd_tilecomp_t* tilec,
+ OPJ_UINT32 numres);
static OPJ_BOOL opj_dwt_encode_procedure(opj_tcd_tilecomp_t * tilec,
void (*p_function)(OPJ_INT32 *, OPJ_INT32, OPJ_INT32, OPJ_INT32));
return opj_dwt_encode_procedure(tilec, opj_dwt_encode_1);
}
-static OPJ_BOOL opj_dwt_is_whole_tile_decoding(opj_tcd_t *p_tcd,
- opj_tcd_tilecomp_t* tilec, OPJ_UINT32 numres)
-{
- opj_image_comp_t* image_comp = &(p_tcd->image->comps[tilec->compno]);
- /* Compute the intersection of the area of interest, expressed in tile coordinates */
- /* with the tile coordinates */
- OPJ_UINT32 tcx0 = opj_uint_max(
- (OPJ_UINT32)tilec->x0,
- opj_uint_ceildiv(p_tcd->decoded_x0, image_comp->dx));
- OPJ_UINT32 tcy0 = opj_uint_max(
- (OPJ_UINT32)tilec->y0,
- opj_uint_ceildiv(p_tcd->decoded_y0, image_comp->dy));
- OPJ_UINT32 tcx1 = opj_uint_min(
- (OPJ_UINT32)tilec->x1,
- opj_uint_ceildiv(p_tcd->decoded_x1, image_comp->dx));
- OPJ_UINT32 tcy1 = opj_uint_min(
- (OPJ_UINT32)tilec->y1,
- opj_uint_ceildiv(p_tcd->decoded_y1, image_comp->dy));
-
- OPJ_UINT32 shift = tilec->numresolutions - numres;
-
- /* Tolerate small margin within the reduced resolution factor to consider if */
- /* the whole tile path must be taken */
- return (tcx0 >= (OPJ_UINT32)tilec->x0 &&
- tcy0 >= (OPJ_UINT32)tilec->y0 &&
- tcx1 <= (OPJ_UINT32)tilec->x1 &&
- tcy1 <= (OPJ_UINT32)tilec->y1 &&
- (shift >= 32 ||
- (((tcx0 - (OPJ_UINT32)tilec->x0) >> shift) == 0 &&
- ((tcy0 - (OPJ_UINT32)tilec->y0) >> shift) == 0 &&
- (((OPJ_UINT32)tilec->x1 - tcx1) >> shift) == 0 &&
- (((OPJ_UINT32)tilec->y1 - tcy1) >> shift) == 0)));
-}
-
/* <summary> */
/* Inverse 5-3 wavelet transform in 2-D. */
/* </summary> */
OPJ_BOOL opj_dwt_decode(opj_tcd_t *p_tcd, opj_tcd_tilecomp_t* tilec,
OPJ_UINT32 numres)
{
- if (opj_dwt_is_whole_tile_decoding(p_tcd, tilec, numres)) {
+ if (p_tcd->whole_tile_decoding) {
return opj_dwt_decode_tile(p_tcd->thread_pool, tilec, numres);
} else {
- return opj_dwt_decode_partial_tile(p_tcd, tilec, numres);
+ return opj_dwt_decode_partial_tile(tilec, numres);
}
}
OPJ_UINT32 rh = (OPJ_UINT32)(tr->y1 -
tr->y0); /* height of the resolution level computed */
- OPJ_UINT32 w = (OPJ_UINT32)(tilec->x1 - tilec->x0);
+ OPJ_UINT32 w = (OPJ_UINT32)(tilec->resolutions[tilec->minimum_num_resolutions -
+ 1].x1 -
+ tilec->resolutions[tilec->minimum_num_resolutions - 1].x0);
size_t h_mem_size;
int num_threads;
static void opj_dwt_interleave_partial_h(OPJ_INT32 *dest,
OPJ_INT32 cas,
- const OPJ_INT32* src,
- OPJ_INT32 sn,
- OPJ_INT32 win_l_x0,
- OPJ_INT32 win_l_x1,
- OPJ_INT32 win_h_x0,
- OPJ_INT32 win_h_x1)
+ opj_sparse_array_int32_t* sa,
+ OPJ_UINT32 sa_line,
+ OPJ_UINT32 sn,
+ OPJ_UINT32 win_l_x0,
+ OPJ_UINT32 win_l_x1,
+ OPJ_UINT32 win_h_x0,
+ OPJ_UINT32 win_h_x1)
{
- const OPJ_INT32 *ai = src;
- OPJ_INT32 *bi = dest + cas;
- OPJ_INT32 i;
-
- for (i = win_l_x0; i < win_l_x1; i++) {
- bi[2 * i] = ai[i];
- }
-
- ai = src + sn;
- bi = dest + 1 - cas;
- for (i = win_h_x0; i < win_h_x1; i++) {
- bi[2 * i] = ai[i];
- }
+ OPJ_BOOL ret;
+ ret = opj_sparse_array_int32_read(sa,
+ win_l_x0, sa_line,
+ win_l_x1, sa_line + 1,
+ dest + cas + 2 * win_l_x0,
+ 2, 0, OPJ_TRUE);
+ assert(ret);
+ ret = opj_sparse_array_int32_read(sa,
+ sn + win_h_x0, sa_line,
+ sn + win_h_x1, sa_line + 1,
+ dest + 1 - cas + 2 * win_h_x0,
+ 2, 0, OPJ_TRUE);
+ assert(ret);
}
+
static void opj_dwt_interleave_partial_v(OPJ_INT32 *dest,
OPJ_INT32 cas,
- const OPJ_INT32* src,
- OPJ_INT32 sn,
- OPJ_INT32 stride,
- OPJ_INT32 win_l_y0,
- OPJ_INT32 win_l_y1,
- OPJ_INT32 win_h_y0,
- OPJ_INT32 win_h_y1)
+ opj_sparse_array_int32_t* sa,
+ OPJ_UINT32 sa_col,
+ OPJ_UINT32 sn,
+ OPJ_UINT32 win_l_y0,
+ OPJ_UINT32 win_l_y1,
+ OPJ_UINT32 win_h_y0,
+ OPJ_UINT32 win_h_y1)
{
- const OPJ_INT32 *ai = src;
- OPJ_INT32 *bi = dest + cas;
- OPJ_INT32 i;
-
- for (i = win_l_y0; i < win_l_y1; i++) {
- bi[2 * i] = ai[i * stride];
- }
-
- ai = src + sn * stride;
- bi = dest + 1 - cas;
- for (i = win_h_y0; i < win_h_y1; i++) {
- bi[2 * i] = ai[i * stride];
- }
+ OPJ_BOOL ret;
+ ret = opj_sparse_array_int32_read(sa,
+ sa_col, win_l_y0,
+ sa_col + 1, win_l_y1,
+ dest + cas + 2 * win_l_y0,
+ 0, 2, OPJ_TRUE);
+ assert(ret);
+ ret = opj_sparse_array_int32_read(sa,
+ sa_col, sn + win_h_y0,
+ sa_col + 1, sn + win_h_y1,
+ dest + 1 - cas + 2 * win_h_y0,
+ 0, 2, OPJ_TRUE);
+ assert(ret);
}
static void opj_dwt_decode_partial_1(OPJ_INT32 *a, OPJ_INT32 dn, OPJ_INT32 sn,
*end = opj_uint_min(*end, max_size);
}
-static OPJ_BOOL opj_dwt_decode_partial_tile(opj_tcd_t *tcd,
- opj_tcd_tilecomp_t* tilec,
- OPJ_UINT32 numres)
+
+static opj_sparse_array_int32_t* opj_dwt_init_sparse_array(
+ opj_tcd_tilecomp_t* tilec,
+ OPJ_UINT32 numres)
+{
+ opj_tcd_resolution_t* tr_max = &(tilec->resolutions[numres - 1]);
+ OPJ_UINT32 w = (OPJ_UINT32)(tr_max->x1 - tr_max->x0);
+ OPJ_UINT32 h = (OPJ_UINT32)(tr_max->y1 - tr_max->y0);
+ OPJ_UINT32 resno, bandno, precno, cblkno;
+ opj_sparse_array_int32_t* sa = opj_sparse_array_int32_create(
+ w, h, opj_uint_min(w, 64), opj_uint_min(h, 64));
+ if (sa == NULL) {
+ return NULL;
+ }
+
+ for (resno = 0; resno < numres; ++resno) {
+ opj_tcd_resolution_t* res = &tilec->resolutions[resno];
+
+ for (bandno = 0; bandno < res->numbands; ++bandno) {
+ opj_tcd_band_t* band = &res->bands[bandno];
+
+ for (precno = 0; precno < res->pw * res->ph; ++precno) {
+ opj_tcd_precinct_t* precinct = &band->precincts[precno];
+ for (cblkno = 0; cblkno < precinct->cw * precinct->ch; ++cblkno) {
+ opj_tcd_cblk_dec_t* cblk = &precinct->cblks.dec[cblkno];
+ if (cblk->decoded_data != NULL) {
+ OPJ_UINT32 x = (OPJ_UINT32)(cblk->x0 - band->x0);
+ OPJ_UINT32 y = (OPJ_UINT32)(cblk->y0 - band->y0);
+ OPJ_UINT32 cblk_w = (OPJ_UINT32)(cblk->x1 - cblk->x0);
+ OPJ_UINT32 cblk_h = (OPJ_UINT32)(cblk->y1 - cblk->y0);
+
+ if (band->bandno & 1) {
+ opj_tcd_resolution_t* pres = &tilec->resolutions[resno - 1];
+ x += (OPJ_UINT32)(pres->x1 - pres->x0);
+ }
+ if (band->bandno & 2) {
+ opj_tcd_resolution_t* pres = &tilec->resolutions[resno - 1];
+ y += (OPJ_UINT32)(pres->y1 - pres->y0);
+ }
+
+ if (!opj_sparse_array_int32_write(sa, x, y,
+ x + cblk_w, y + cblk_h,
+ cblk->decoded_data,
+ 1, cblk_w, OPJ_TRUE)) {
+ opj_sparse_array_int32_free(sa);
+ return NULL;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return sa;
+}
+
+
+static OPJ_BOOL opj_dwt_decode_partial_tile(
+ opj_tcd_tilecomp_t* tilec,
+ OPJ_UINT32 numres)
{
+ opj_sparse_array_int32_t* sa;
opj_dwt_t h;
opj_dwt_t v;
OPJ_UINT32 resno;
const OPJ_UINT32 filter_width = 2U;
opj_tcd_resolution_t* tr = tilec->resolutions;
+ opj_tcd_resolution_t* tr_max = &(tilec->resolutions[numres - 1]);
OPJ_UINT32 rw = (OPJ_UINT32)(tr->x1 -
tr->x0); /* width of the resolution level computed */
OPJ_UINT32 rh = (OPJ_UINT32)(tr->y1 -
tr->y0); /* height of the resolution level computed */
- OPJ_UINT32 w = (OPJ_UINT32)(tilec->x1 - tilec->x0);
size_t h_mem_size;
- opj_image_comp_t* image_comp = &(tcd->image->comps[tilec->compno]);
/* Compute the intersection of the area of interest, expressed in tile coordinates */
/* with the tile coordinates */
- OPJ_UINT32 win_tcx0 = opj_uint_max(
- (OPJ_UINT32)tilec->x0,
- opj_uint_ceildiv(tcd->decoded_x0, image_comp->dx));
- OPJ_UINT32 win_tcy0 = opj_uint_max(
- (OPJ_UINT32)tilec->y0,
- opj_uint_ceildiv(tcd->decoded_y0, image_comp->dy));
- OPJ_UINT32 win_tcx1 = opj_uint_min(
- (OPJ_UINT32)tilec->x1,
- opj_uint_ceildiv(tcd->decoded_x1, image_comp->dx));
- OPJ_UINT32 win_tcy1 = opj_uint_min(
- (OPJ_UINT32)tilec->y1,
- opj_uint_ceildiv(tcd->decoded_y1, image_comp->dy));
+ OPJ_UINT32 win_tcx0 = tilec->win_x0;
+ OPJ_UINT32 win_tcy0 = tilec->win_y0;
+ OPJ_UINT32 win_tcx1 = tilec->win_x1;
+ OPJ_UINT32 win_tcy1 = tilec->win_y1;
+
+ sa = opj_dwt_init_sparse_array(tilec, numres);
if (numres == 1U) {
+ OPJ_BOOL ret = opj_sparse_array_int32_read(sa,
+ tr_max->win_x0 - (OPJ_UINT32)tr_max->x0,
+ tr_max->win_y0 - (OPJ_UINT32)tr_max->y0,
+ tr_max->win_x1 - (OPJ_UINT32)tr_max->x0,
+ tr_max->win_y1 - (OPJ_UINT32)tr_max->y0,
+ tilec->data_win,
+ 1, tr_max->win_x1 - tr_max->win_x0,
+ OPJ_TRUE);
+ assert(ret);
+ opj_sparse_array_int32_free(sa);
return OPJ_TRUE;
}
h_mem_size = opj_dwt_max_resolution(tr, numres);
/* overflow check */
if (h_mem_size > (SIZE_MAX / sizeof(OPJ_INT32))) {
/* FIXME event manager error callback */
+ opj_sparse_array_int32_free(sa);
return OPJ_FALSE;
}
h.mem = (OPJ_INT32*)opj_aligned_32_malloc(h_mem_size);
if (! h.mem) {
/* FIXME event manager error callback */
+ opj_sparse_array_int32_free(sa);
return OPJ_FALSE;
}
v.mem = h.mem;
- for (resno = 1; --numres > 0; resno ++) {
- OPJ_INT32 * OPJ_RESTRICT tiledp = tilec->data;
+ for (resno = 1; resno < numres; resno ++) {
OPJ_UINT32 i, j;
/* Window of interest subband-based coordinates */
OPJ_UINT32 win_ll_x0, win_ll_y0, win_ll_x1, win_ll_y1;
for (j = 0; j < rh; ++j) {
if ((j >= win_ll_y0 && j < win_ll_y1) ||
(j >= win_lh_y0 + (OPJ_UINT32)v.sn && j < win_lh_y1 + (OPJ_UINT32)v.sn)) {
- memset(h.mem, 0, (OPJ_UINT32)(h.sn + h.dn) * sizeof(OPJ_INT32));
opj_dwt_interleave_partial_h(h.mem,
h.cas,
- &tiledp[j * w],
- h.sn,
- (OPJ_INT32)win_ll_x0,
- (OPJ_INT32)win_ll_x1,
- (OPJ_INT32)win_hl_x0,
- (OPJ_INT32)win_hl_x1);
+ sa,
+ j,
+ (OPJ_UINT32)h.sn,
+ win_ll_x0,
+ win_ll_x1,
+ win_hl_x0,
+ win_hl_x1);
opj_dwt_decode_partial_1(h.mem, h.dn, h.sn, h.cas,
(OPJ_INT32)win_ll_x0,
(OPJ_INT32)win_ll_x1,
(OPJ_INT32)win_hl_x0,
(OPJ_INT32)win_hl_x1);
- memcpy(&tiledp[j * w] + win_tr_x0, h.mem + win_tr_x0,
- (win_tr_x1 - win_tr_x0) * sizeof(OPJ_INT32));
+ if (!opj_sparse_array_int32_write(sa,
+ win_tr_x0, j,
+ win_tr_x1, j + 1,
+ h.mem + win_tr_x0,
+ 1, 0, OPJ_TRUE)) {
+ /* FIXME event manager error callback */
+ opj_sparse_array_int32_free(sa);
+ opj_aligned_free(h.mem);
+ return OPJ_FALSE;
+ }
}
}
for (i = win_tr_x0; i < win_tr_x1; ++i) {
- memset(v.mem, 0, (OPJ_UINT32)(v.sn + v.dn) * sizeof(OPJ_INT32));
opj_dwt_interleave_partial_v(v.mem,
v.cas,
- tiledp + i,
- v.sn,
- (OPJ_INT32)w,
- (OPJ_INT32)win_ll_y0,
- (OPJ_INT32)win_ll_y1,
- (OPJ_INT32)win_lh_y0,
- (OPJ_INT32)win_lh_y1);
+ sa,
+ i,
+ (OPJ_UINT32)v.sn,
+ win_ll_y0,
+ win_ll_y1,
+ win_lh_y0,
+ win_lh_y1);
opj_dwt_decode_partial_1(v.mem, v.dn, v.sn, v.cas,
(OPJ_INT32)win_ll_y0,
(OPJ_INT32)win_ll_y1,
(OPJ_INT32)win_lh_y0,
(OPJ_INT32)win_lh_y1);
- for (j = win_tr_y0; j < win_tr_y1; j++) {
- tiledp[j * w + i] = v.mem[j];
+ if (!opj_sparse_array_int32_write(sa,
+ i, win_tr_y0,
+ i + 1, win_tr_y1,
+ v.mem + win_tr_y0,
+ 0, 1, OPJ_TRUE)) {
+ /* FIXME event manager error callback */
+ opj_sparse_array_int32_free(sa);
+ opj_aligned_free(h.mem);
+ return OPJ_FALSE;
}
}
}
opj_aligned_free(h.mem);
+
+ {
+ OPJ_BOOL ret = opj_sparse_array_int32_read(sa,
+ tr_max->win_x0 - (OPJ_UINT32)tr_max->x0,
+ tr_max->win_y0 - (OPJ_UINT32)tr_max->y0,
+ tr_max->win_x1 - (OPJ_UINT32)tr_max->x0,
+ tr_max->win_y1 - (OPJ_UINT32)tr_max->y0,
+ tilec->data_win,
+ 1, tr_max->win_x1 - tr_max->win_x0,
+ OPJ_TRUE);
+ assert(ret);
+ }
+ opj_sparse_array_int32_free(sa);
return OPJ_TRUE;
}
}
}
+static void opj_v4dwt_interleave_partial_h(opj_v4dwt_t* dwt,
+ opj_sparse_array_int32_t* sa,
+ OPJ_UINT32 sa_line,
+ OPJ_UINT32 remaining_height)
+{
+ OPJ_UINT32 i;
+ for (i = 0; i < remaining_height; i++) {
+ OPJ_BOOL ret;
+ ret = opj_sparse_array_int32_read(sa,
+ dwt->win_l_x0, sa_line + i,
+ dwt->win_l_x1, sa_line + i + 1,
+ /* Nasty cast from float* to int32* */
+ (OPJ_INT32*)(dwt->wavelet + dwt->cas + 2 * dwt->win_l_x0) + i,
+ 8, 0, OPJ_TRUE);
+ assert(ret);
+ ret = opj_sparse_array_int32_read(sa,
+ (OPJ_UINT32)dwt->sn + dwt->win_h_x0, sa_line + i,
+ (OPJ_UINT32)dwt->sn + dwt->win_h_x1, sa_line + i + 1,
+ /* Nasty cast from float* to int32* */
+ (OPJ_INT32*)(dwt->wavelet + 1 - dwt->cas + 2 * dwt->win_h_x0) + i,
+ 8, 0, OPJ_TRUE);
+ assert(ret);
+ }
+}
+
static void opj_v4dwt_interleave_v(opj_v4dwt_t* OPJ_RESTRICT dwt,
OPJ_FLOAT32* OPJ_RESTRICT a,
OPJ_UINT32 width,
}
}
+static void opj_v4dwt_interleave_partial_v(opj_v4dwt_t* OPJ_RESTRICT dwt,
+ opj_sparse_array_int32_t* sa,
+ OPJ_UINT32 sa_col,
+ OPJ_UINT32 nb_elts_read)
+{
+ OPJ_UINT32 i;
+ for (i = 0; i < nb_elts_read; i++) {
+ OPJ_BOOL ret;
+ ret = opj_sparse_array_int32_read(sa,
+ sa_col + i, dwt->win_l_x0,
+ sa_col + i + 1, dwt->win_l_x1,
+ (OPJ_INT32*)(dwt->wavelet + dwt->cas + 2 * dwt->win_l_x0) + i,
+ 0, 8, OPJ_TRUE);
+ assert(ret);
+ ret = opj_sparse_array_int32_read(sa,
+ sa_col + i, (OPJ_UINT32)dwt->sn + dwt->win_h_x0,
+ sa_col + i + 1, (OPJ_UINT32)dwt->sn + dwt->win_h_x1,
+ (OPJ_INT32*)(dwt->wavelet + 1 - dwt->cas + 2 * dwt->win_h_x0) + i,
+ 0, 8, OPJ_TRUE);
+ assert(ret);
+ }
+}
+
#ifdef __SSE__
static void opj_v4dwt_decode_step1_sse(opj_v4_t* w,
OPJ_UINT32 rh = (OPJ_UINT32)(res->y1 -
res->y0); /* height of the resolution level computed */
- OPJ_UINT32 w = (OPJ_UINT32)(tilec->x1 - tilec->x0);
+ OPJ_UINT32 w = (OPJ_UINT32)(tilec->resolutions[tilec->minimum_num_resolutions -
+ 1].x1 -
+ tilec->resolutions[tilec->minimum_num_resolutions - 1].x0);
size_t l_data_size;
}
static
-OPJ_BOOL opj_dwt_decode_partial_97(opj_tcd_t *tcd,
- opj_tcd_tilecomp_t* OPJ_RESTRICT tilec,
+OPJ_BOOL opj_dwt_decode_partial_97(opj_tcd_tilecomp_t* OPJ_RESTRICT tilec,
OPJ_UINT32 numres)
{
+ opj_sparse_array_int32_t* sa;
opj_v4dwt_t h;
opj_v4dwt_t v;
OPJ_UINT32 resno;
const OPJ_UINT32 filter_width = 4U;
opj_tcd_resolution_t* tr = tilec->resolutions;
+ opj_tcd_resolution_t* tr_max = &(tilec->resolutions[numres - 1]);
OPJ_UINT32 rw = (OPJ_UINT32)(tr->x1 -
tr->x0); /* width of the resolution level computed */
OPJ_UINT32 rh = (OPJ_UINT32)(tr->y1 -
tr->y0); /* height of the resolution level computed */
- OPJ_UINT32 w = (OPJ_UINT32)(tilec->x1 - tilec->x0);
-
size_t l_data_size;
- opj_image_comp_t* image_comp = &(tcd->image->comps[tilec->compno]);
/* Compute the intersection of the area of interest, expressed in tile coordinates */
/* with the tile coordinates */
- OPJ_UINT32 win_tcx0 = opj_uint_max(
- (OPJ_UINT32)tilec->x0,
- opj_uint_ceildiv(tcd->decoded_x0, image_comp->dx));
- OPJ_UINT32 win_tcy0 = opj_uint_max(
- (OPJ_UINT32)tilec->y0,
- opj_uint_ceildiv(tcd->decoded_y0, image_comp->dy));
- OPJ_UINT32 win_tcx1 = opj_uint_min(
- (OPJ_UINT32)tilec->x1,
- opj_uint_ceildiv(tcd->decoded_x1, image_comp->dx));
- OPJ_UINT32 win_tcy1 = opj_uint_min(
- (OPJ_UINT32)tilec->y1,
- opj_uint_ceildiv(tcd->decoded_y1, image_comp->dy));
+ OPJ_UINT32 win_tcx0 = tilec->win_x0;
+ OPJ_UINT32 win_tcy0 = tilec->win_y0;
+ OPJ_UINT32 win_tcx1 = tilec->win_x1;
+ OPJ_UINT32 win_tcy1 = tilec->win_y1;
+
+ sa = opj_dwt_init_sparse_array(tilec, numres);
+
+ if (numres == 1U) {
+ OPJ_BOOL ret = opj_sparse_array_int32_read(sa,
+ tr_max->win_x0 - (OPJ_UINT32)tr_max->x0,
+ tr_max->win_y0 - (OPJ_UINT32)tr_max->y0,
+ tr_max->win_x1 - (OPJ_UINT32)tr_max->x0,
+ tr_max->win_y1 - (OPJ_UINT32)tr_max->y0,
+ tilec->data_win,
+ 1, tr_max->win_x1 - tr_max->win_x0,
+ OPJ_TRUE);
+ assert(ret);
+ opj_sparse_array_int32_free(sa);
+ return OPJ_TRUE;
+ }
l_data_size = opj_dwt_max_resolution(tr, numres);
/* overflow check */
}
v.wavelet = h.wavelet;
- for (resno = 1; --numres; resno++) {
- OPJ_FLOAT32 * OPJ_RESTRICT aj = (OPJ_FLOAT32*) tilec->data;
+ for (resno = 1; resno < numres; resno ++) {
OPJ_UINT32 j;
/* Window of interest subband-based coordinates */
OPJ_UINT32 win_ll_x0, win_ll_y0, win_ll_x1, win_ll_y1;
h.win_l_x1 = win_ll_x1;
h.win_h_x0 = win_hl_x0;
h.win_h_x1 = win_hl_x1;
- for (j = 0; j + 3 < rh; j += 4, aj += w * 4) {
+ for (j = 0; j + 3 < rh; j += 4) {
if ((j + 3 >= win_ll_y0 && j < win_ll_y1) ||
(j + 3 >= win_lh_y0 + (OPJ_UINT32)v.sn &&
j < win_lh_y1 + (OPJ_UINT32)v.sn)) {
OPJ_UINT32 k;
- opj_v4dwt_interleave_h(&h, aj, w, rh - j);
+ opj_v4dwt_interleave_partial_h(&h, sa, j, opj_uint_min(4U, rh - j));
opj_v4dwt_decode(&h);
-
- for (k = win_tr_x0; k < win_tr_x1; k++) {
- aj[k ] = h.wavelet[k].f[0];
- aj[k + w ] = h.wavelet[k].f[1];
- aj[k + w * 2] = h.wavelet[k].f[2];
- aj[k + w * 3] = h.wavelet[k].f[3];
+ for (k = 0; k < 4; k++) {
+ if (!opj_sparse_array_int32_write(sa,
+ win_tr_x0, j + k,
+ win_tr_x1, j + k + 1,
+ (OPJ_INT32*)&h.wavelet[win_tr_x0].f[k],
+ 4, 0, OPJ_TRUE)) {
+ /* FIXME event manager error callback */
+ opj_sparse_array_int32_free(sa);
+ opj_aligned_free(h.wavelet);
+ return OPJ_FALSE;
+ }
}
}
}
(j + 3 >= win_lh_y0 + (OPJ_UINT32)v.sn &&
j < win_lh_y1 + (OPJ_UINT32)v.sn))) {
OPJ_UINT32 k;
- opj_v4dwt_interleave_h(&h, aj, w, rh - j);
+ opj_v4dwt_interleave_partial_h(&h, sa, j, rh - j);
opj_v4dwt_decode(&h);
- for (k = win_tr_x0; k < win_tr_x1; k++) {
- switch (rh - j) {
- case 3:
- aj[k + w * 2] = h.wavelet[k].f[2];
- /* FALLTHRU */
- case 2:
- aj[k + w ] = h.wavelet[k].f[1];
- /* FALLTHRU */
- case 1:
- aj[k ] = h.wavelet[k].f[0];
+ for (k = 0; k < rh - j; k++) {
+ if (!opj_sparse_array_int32_write(sa,
+ win_tr_x0, j + k,
+ win_tr_x1, j + k + 1,
+ (OPJ_INT32*)&h.wavelet[win_tr_x0].f[k],
+ 4, 0, OPJ_TRUE)) {
+ /* FIXME event manager error callback */
+ opj_sparse_array_int32_free(sa);
+ opj_aligned_free(h.wavelet);
+ return OPJ_FALSE;
}
}
}
v.win_l_x1 = win_ll_y1;
v.win_h_x0 = win_lh_y0;
v.win_h_x1 = win_lh_y1;
- aj = (OPJ_FLOAT32*) tilec->data;
- aj += win_tr_x0;
- for (j = win_tr_x0; j < win_tr_x1; j += 4, aj += 4) {
+ for (j = win_tr_x0; j < win_tr_x1; j += 4) {
OPJ_UINT32 nb_elts = opj_uint_min(4U, win_tr_x1 - j);
OPJ_UINT32 k;
- opj_v4dwt_interleave_v(&v, aj, w, nb_elts);
+ opj_v4dwt_interleave_partial_v(&v, sa, j, nb_elts);
opj_v4dwt_decode(&v);
- for (k = win_tr_y0; k < win_tr_y1; ++k) {
- memcpy(&aj[k * w], &v.wavelet[k], nb_elts * sizeof(OPJ_FLOAT32));
+ for (k = 0; k < nb_elts; k++) {
+ if (!opj_sparse_array_int32_write(sa,
+ j + k, win_tr_y0,
+ j + k + 1, win_tr_y1,
+ (OPJ_INT32*)&h.wavelet[win_tr_y0].f[k],
+ 0, 4, OPJ_TRUE)) {
+ /* FIXME event manager error callback */
+ opj_sparse_array_int32_free(sa);
+ opj_aligned_free(h.wavelet);
+ return OPJ_FALSE;
+ }
}
}
}
+ {
+ OPJ_BOOL ret = opj_sparse_array_int32_read(sa,
+ tr_max->win_x0 - (OPJ_UINT32)tr_max->x0,
+ tr_max->win_y0 - (OPJ_UINT32)tr_max->y0,
+ tr_max->win_x1 - (OPJ_UINT32)tr_max->x0,
+ tr_max->win_y1 - (OPJ_UINT32)tr_max->y0,
+ tilec->data_win,
+ 1, tr_max->win_x1 - tr_max->win_x0,
+ OPJ_TRUE);
+ assert(ret);
+ }
+ opj_sparse_array_int32_free(sa);
+
opj_aligned_free(h.wavelet);
return OPJ_TRUE;
}
opj_tcd_tilecomp_t* OPJ_RESTRICT tilec,
OPJ_UINT32 numres)
{
- if (opj_dwt_is_whole_tile_decoding(p_tcd, tilec, numres)) {
+ if (p_tcd->whole_tile_decoding) {
return opj_dwt_decode_tile_97(tilec, numres);
} else {
- return opj_dwt_decode_partial_97(p_tcd, tilec, numres);
+ return opj_dwt_decode_partial_97(tilec, numres);
}
}
/**
Inverse 5-3 wavelet transform in 2-D.
Apply a reversible inverse DWT transform to a component of an image.
-@param tcd TCD handle
+@param p_tcd TCD handle
@param tilec Tile component information (current tile)
@param numres Number of resolution levels to decode
*/
/**
Inverse 9-7 wavelet transform in 2-D.
Apply an irreversible inverse DWT transform to a component of an image.
-@param tcd TCD handle
+@param p_tcd TCD handle
@param tilec Tile component information (current tile)
@param numres Number of resolution levels to decode
*/
/** @name Local static functions */
/*@{*/
-#define OPJ_UNUSED(x) (void)x
-
/**
* Sets up the procedures to do on reading header. Developpers wanting to extend the library can add their own reading procedures.
*/
opj_stream_private_t *p_stream,
opj_event_mgr_t * p_manager);
-static OPJ_BOOL opj_j2k_update_image_data(opj_tcd_t * p_tcd, OPJ_BYTE * p_data,
+static OPJ_BOOL opj_j2k_update_image_data(opj_tcd_t * p_tcd,
opj_image_t* p_output_image);
static void opj_get_tile_dimensions(opj_image_t * l_image,
*p_tile_index = p_j2k->m_current_tile_number;
*p_go_on = OPJ_TRUE;
- *p_data_size = opj_tcd_get_decoded_tile_size(p_j2k->m_tcd);
+ *p_data_size = opj_tcd_get_decoded_tile_size(p_j2k->m_tcd, OPJ_FALSE);
if (*p_data_size == UINT_MAX) {
return OPJ_FALSE;
}
return OPJ_TRUE;
}
-static OPJ_BOOL opj_j2k_update_image_data(opj_tcd_t * p_tcd, OPJ_BYTE * p_data,
+static OPJ_BOOL opj_j2k_update_image_data(opj_tcd_t * p_tcd,
opj_image_t* p_output_image)
{
- OPJ_UINT32 i, j, k = 0;
+ OPJ_UINT32 i, j;
OPJ_UINT32 l_width_src, l_height_src;
OPJ_UINT32 l_width_dest, l_height_dest;
OPJ_INT32 l_offset_x0_src, l_offset_y0_src, l_offset_x1_src, l_offset_y1_src;
- OPJ_SIZE_T l_start_offset_src, l_line_offset_src, l_end_offset_src ;
+ OPJ_SIZE_T l_start_offset_src;
OPJ_UINT32 l_start_x_dest, l_start_y_dest;
OPJ_UINT32 l_x0_dest, l_y0_dest, l_x1_dest, l_y1_dest;
- OPJ_SIZE_T l_start_offset_dest, l_line_offset_dest;
+ OPJ_SIZE_T l_start_offset_dest;
opj_image_comp_t * l_img_comp_src = 00;
opj_image_comp_t * l_img_comp_dest = 00;
opj_tcd_tilecomp_t * l_tilec = 00;
opj_image_t * l_image_src = 00;
- OPJ_UINT32 l_size_comp, l_remaining;
OPJ_INT32 * l_dest_ptr;
- opj_tcd_resolution_t* l_res = 00;
l_tilec = p_tcd->tcd_image->tiles->comps;
l_image_src = p_tcd->image;
l_img_comp_dest = p_output_image->comps;
for (i = 0; i < l_image_src->numcomps; i++) {
+ OPJ_INT32 res_x0, res_x1, res_y0, res_y1;
+ OPJ_UINT32 src_data_stride;
+ const OPJ_INT32* p_src_data;
/* Allocate output component buffer if necessary */
if (!l_img_comp_dest->data) {
/* Copy info from decoded comp image to output image */
l_img_comp_dest->resno_decoded = l_img_comp_src->resno_decoded;
- /*-----*/
- /* Compute the precision of the output buffer */
- l_size_comp = l_img_comp_src->prec >> 3; /*(/ 8)*/
- l_remaining = l_img_comp_src->prec & 7; /* (%8) */
- l_res = l_tilec->resolutions + l_img_comp_src->resno_decoded;
-
- if (l_remaining) {
- ++l_size_comp;
+ if (p_tcd->whole_tile_decoding) {
+ opj_tcd_resolution_t* l_res = l_tilec->resolutions +
+ l_img_comp_src->resno_decoded;
+ res_x0 = l_res->x0;
+ res_y0 = l_res->y0;
+ res_x1 = l_res->x1;
+ res_y1 = l_res->y1;
+ src_data_stride = (OPJ_UINT32)(
+ l_tilec->resolutions[l_tilec->minimum_num_resolutions - 1].x1 -
+ l_tilec->resolutions[l_tilec->minimum_num_resolutions - 1].x0);
+ p_src_data = l_tilec->data;
+ } else {
+ opj_tcd_resolution_t* l_res = l_tilec->resolutions +
+ l_img_comp_src->resno_decoded;
+ res_x0 = (OPJ_INT32)l_res->win_x0;
+ res_y0 = (OPJ_INT32)l_res->win_y0;
+ res_x1 = (OPJ_INT32)l_res->win_x1;
+ res_y1 = (OPJ_INT32)l_res->win_y1;
+ src_data_stride = l_res->win_x1 - l_res->win_x0;
+ p_src_data = l_tilec->data_win;
}
- if (l_size_comp == 3) {
- l_size_comp = 4;
- }
- /*-----*/
+ l_width_src = (OPJ_UINT32)(res_x1 - res_x0);
+ l_height_src = (OPJ_UINT32)(res_y1 - res_y0);
+
/* Current tile component size*/
/*if (i == 0) {
fprintf(stdout, "SRC: l_res_x0=%d, l_res_x1=%d, l_res_y0=%d, l_res_y1=%d\n",
- l_res->x0, l_res->x1, l_res->y0, l_res->y1);
+ res_x0, res_x1, res_y0, res_y1);
}*/
- l_width_src = (OPJ_UINT32)(l_res->x1 - l_res->x0);
- l_height_src = (OPJ_UINT32)(l_res->y1 - l_res->y0);
/* Border of the current output component*/
l_x0_dest = opj_uint_ceildivpow2(l_img_comp_dest->x0, l_img_comp_dest->factor);
* l_start_y_dest, l_width_dest, l_height_dest) which will be modified
* by this input area.
* */
- assert(l_res->x0 >= 0);
- assert(l_res->x1 >= 0);
- if (l_x0_dest < (OPJ_UINT32)l_res->x0) {
- l_start_x_dest = (OPJ_UINT32)l_res->x0 - l_x0_dest;
+ assert(res_x0 >= 0);
+ assert(res_x1 >= 0);
+ if (l_x0_dest < (OPJ_UINT32)res_x0) {
+ l_start_x_dest = (OPJ_UINT32)res_x0 - l_x0_dest;
l_offset_x0_src = 0;
- if (l_x1_dest >= (OPJ_UINT32)l_res->x1) {
+ if (l_x1_dest >= (OPJ_UINT32)res_x1) {
l_width_dest = l_width_src;
l_offset_x1_src = 0;
} else {
- l_width_dest = l_x1_dest - (OPJ_UINT32)l_res->x0 ;
+ l_width_dest = l_x1_dest - (OPJ_UINT32)res_x0 ;
l_offset_x1_src = (OPJ_INT32)(l_width_src - l_width_dest);
}
} else {
l_start_x_dest = 0U;
- l_offset_x0_src = (OPJ_INT32)l_x0_dest - l_res->x0;
+ l_offset_x0_src = (OPJ_INT32)l_x0_dest - res_x0;
- if (l_x1_dest >= (OPJ_UINT32)l_res->x1) {
+ if (l_x1_dest >= (OPJ_UINT32)res_x1) {
l_width_dest = l_width_src - (OPJ_UINT32)l_offset_x0_src;
l_offset_x1_src = 0;
} else {
l_width_dest = l_img_comp_dest->w ;
- l_offset_x1_src = l_res->x1 - (OPJ_INT32)l_x1_dest;
+ l_offset_x1_src = res_x1 - (OPJ_INT32)l_x1_dest;
}
}
- if (l_y0_dest < (OPJ_UINT32)l_res->y0) {
- l_start_y_dest = (OPJ_UINT32)l_res->y0 - l_y0_dest;
+ if (l_y0_dest < (OPJ_UINT32)res_y0) {
+ l_start_y_dest = (OPJ_UINT32)res_y0 - l_y0_dest;
l_offset_y0_src = 0;
- if (l_y1_dest >= (OPJ_UINT32)l_res->y1) {
+ if (l_y1_dest >= (OPJ_UINT32)res_y1) {
l_height_dest = l_height_src;
l_offset_y1_src = 0;
} else {
- l_height_dest = l_y1_dest - (OPJ_UINT32)l_res->y0 ;
+ l_height_dest = l_y1_dest - (OPJ_UINT32)res_y0 ;
l_offset_y1_src = (OPJ_INT32)(l_height_src - l_height_dest);
}
} else {
l_start_y_dest = 0U;
- l_offset_y0_src = (OPJ_INT32)l_y0_dest - l_res->y0;
+ l_offset_y0_src = (OPJ_INT32)l_y0_dest - res_y0;
- if (l_y1_dest >= (OPJ_UINT32)l_res->y1) {
+ if (l_y1_dest >= (OPJ_UINT32)res_y1) {
l_height_dest = l_height_src - (OPJ_UINT32)l_offset_y0_src;
l_offset_y1_src = 0;
} else {
l_height_dest = l_img_comp_dest->h ;
- l_offset_y1_src = l_res->y1 - (OPJ_INT32)l_y1_dest;
+ l_offset_y1_src = res_y1 - (OPJ_INT32)l_y1_dest;
}
}
/* Compute the input buffer offset */
l_start_offset_src = (OPJ_SIZE_T)l_offset_x0_src + (OPJ_SIZE_T)l_offset_y0_src
- * (OPJ_SIZE_T)l_width_src;
- l_line_offset_src = (OPJ_SIZE_T)l_offset_x1_src + (OPJ_SIZE_T)l_offset_x0_src;
- l_end_offset_src = (OPJ_SIZE_T)l_offset_y1_src * (OPJ_SIZE_T)l_width_src -
- (OPJ_SIZE_T)l_offset_x0_src;
+ * (OPJ_SIZE_T)src_data_stride;
/* Compute the output buffer offset */
l_start_offset_dest = (OPJ_SIZE_T)l_start_x_dest + (OPJ_SIZE_T)l_start_y_dest
* (OPJ_SIZE_T)l_img_comp_dest->w;
- l_line_offset_dest = (OPJ_SIZE_T)l_img_comp_dest->w - (OPJ_SIZE_T)l_width_dest;
/* Move the output buffer to the first place where we will write*/
l_dest_ptr = l_img_comp_dest->data + l_start_offset_dest;
- /*if (i == 0) {
- fprintf(stdout, "COMPO[%d]:\n",i);
- fprintf(stdout, "SRC: l_start_x_src=%d, l_start_y_src=%d, l_width_src=%d, l_height_src=%d\n"
- "\t tile offset:%d, %d, %d, %d\n"
- "\t buffer offset: %d; %d, %d\n",
- l_res->x0, l_res->y0, l_width_src, l_height_src,
- l_offset_x0_src, l_offset_y0_src, l_offset_x1_src, l_offset_y1_src,
- l_start_offset_src, l_line_offset_src, l_end_offset_src);
-
- fprintf(stdout, "DEST: l_start_x_dest=%d, l_start_y_dest=%d, l_width_dest=%d, l_height_dest=%d\n"
- "\t start offset: %d, line offset= %d\n",
- l_start_x_dest, l_start_y_dest, l_width_dest, l_height_dest, l_start_offset_dest, l_line_offset_dest);
- }*/
-
- switch (l_size_comp) {
- case 1: {
- OPJ_CHAR * l_src_ptr = (OPJ_CHAR*) p_data;
- l_src_ptr += l_start_offset_src; /* Move to the first place where we will read*/
-
- if (l_img_comp_src->sgnd) {
- for (j = 0 ; j < l_height_dest ; ++j) {
- for (k = 0 ; k < l_width_dest ; ++k) {
- *(l_dest_ptr++) = (OPJ_INT32)(*
- (l_src_ptr++)); /* Copy only the data needed for the output image */
- }
-
- l_dest_ptr +=
- l_line_offset_dest; /* Move to the next place where we will write */
- l_src_ptr += l_line_offset_src ; /* Move to the next place where we will read */
- }
- } else {
- for (j = 0 ; j < l_height_dest ; ++j) {
- for (k = 0 ; k < l_width_dest ; ++k) {
- *(l_dest_ptr++) = (OPJ_INT32)((*(l_src_ptr++)) & 0xff);
- }
-
- l_dest_ptr += l_line_offset_dest;
- l_src_ptr += l_line_offset_src;
- }
- }
-
- l_src_ptr +=
- l_end_offset_src; /* Move to the end of this component-part of the input buffer */
- p_data = (OPJ_BYTE*)
- l_src_ptr; /* Keep the current position for the next component-part */
- }
- break;
- case 2: {
- OPJ_INT16 * l_src_ptr = (OPJ_INT16 *) p_data;
- l_src_ptr += l_start_offset_src;
-
- if (l_img_comp_src->sgnd) {
- for (j = 0; j < l_height_dest; ++j) {
- for (k = 0; k < l_width_dest; ++k) {
- OPJ_INT16 val;
- memcpy(&val, l_src_ptr, sizeof(val));
- l_src_ptr ++;
- *(l_dest_ptr++) = val;
- }
-
- l_dest_ptr += l_line_offset_dest;
- l_src_ptr += l_line_offset_src ;
- }
- } else {
- for (j = 0; j < l_height_dest; ++j) {
- for (k = 0; k < l_width_dest; ++k) {
- OPJ_INT16 val;
- memcpy(&val, l_src_ptr, sizeof(val));
- l_src_ptr ++;
- *(l_dest_ptr++) = val & 0xffff;
- }
-
- l_dest_ptr += l_line_offset_dest;
- l_src_ptr += l_line_offset_src ;
- }
- }
-
- l_src_ptr += l_end_offset_src;
- p_data = (OPJ_BYTE*) l_src_ptr;
- }
- break;
- case 4: {
- OPJ_INT32 * l_src_ptr = (OPJ_INT32 *) p_data;
+ {
+ const OPJ_INT32 * l_src_ptr = p_src_data;
l_src_ptr += l_start_offset_src;
for (j = 0; j < l_height_dest; ++j) {
memcpy(l_dest_ptr, l_src_ptr, l_width_dest * sizeof(OPJ_INT32));
- l_dest_ptr += l_width_dest + l_line_offset_dest;
- l_src_ptr += l_width_dest + l_line_offset_src ;
+ l_dest_ptr += l_img_comp_dest->w;
+ l_src_ptr += src_data_stride;
}
-
- l_src_ptr += l_end_offset_src;
- p_data = (OPJ_BYTE*) l_src_ptr;
- }
- break;
}
++l_img_comp_dest;
{
OPJ_BOOL l_go_on = OPJ_TRUE;
OPJ_UINT32 l_current_tile_no;
- OPJ_UINT32 l_data_size, l_max_data_size;
+ OPJ_UINT32 l_data_size;
OPJ_INT32 l_tile_x0, l_tile_y0, l_tile_x1, l_tile_y1;
OPJ_UINT32 l_nb_comps;
- OPJ_BYTE * l_current_data;
OPJ_UINT32 nr_tiles = 0;
/* Particular case for whole single tile decoding */
return OPJ_TRUE;
}
- l_current_data = (OPJ_BYTE*)opj_malloc(1000);
- if (! l_current_data) {
- opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to decode tiles\n");
- return OPJ_FALSE;
- }
- l_max_data_size = 1000;
-
for (;;) {
if (! opj_j2k_read_tile_header(p_j2k,
&l_current_tile_no,
&l_go_on,
p_stream,
p_manager)) {
- opj_free(l_current_data);
return OPJ_FALSE;
}
break;
}
- if (l_data_size > l_max_data_size) {
- OPJ_BYTE *l_new_current_data = (OPJ_BYTE *) opj_realloc(l_current_data,
- l_data_size);
- if (! l_new_current_data) {
- opj_free(l_current_data);
- opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to decode tile %d/%d\n",
- l_current_tile_no + 1, p_j2k->m_cp.th * p_j2k->m_cp.tw);
- return OPJ_FALSE;
- }
- l_current_data = l_new_current_data;
- l_max_data_size = l_data_size;
- }
-
- if (! opj_j2k_decode_tile(p_j2k, l_current_tile_no, l_current_data, l_data_size,
+ if (! opj_j2k_decode_tile(p_j2k, l_current_tile_no, NULL, 0,
p_stream, p_manager)) {
- opj_free(l_current_data);
opj_event_msg(p_manager, EVT_ERROR, "Failed to decode tile %d/%d\n",
l_current_tile_no + 1, p_j2k->m_cp.th * p_j2k->m_cp.tw);
return OPJ_FALSE;
}
+
opj_event_msg(p_manager, EVT_INFO, "Tile %d/%d has been decoded.\n",
l_current_tile_no + 1, p_j2k->m_cp.th * p_j2k->m_cp.tw);
- if (! opj_j2k_update_image_data(p_j2k->m_tcd, l_current_data,
+ if (! opj_j2k_update_image_data(p_j2k->m_tcd,
p_j2k->m_output_image)) {
- opj_free(l_current_data);
return OPJ_FALSE;
}
+ 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);
}
}
- opj_free(l_current_data);
-
return OPJ_TRUE;
}
OPJ_BOOL l_go_on = OPJ_TRUE;
OPJ_UINT32 l_current_tile_no;
OPJ_UINT32 l_tile_no_to_dec;
- OPJ_UINT32 l_data_size, l_max_data_size;
+ OPJ_UINT32 l_data_size;
OPJ_INT32 l_tile_x0, l_tile_y0, l_tile_x1, l_tile_y1;
OPJ_UINT32 l_nb_comps;
- OPJ_BYTE * l_current_data;
OPJ_UINT32 l_nb_tiles;
OPJ_UINT32 i;
- l_current_data = (OPJ_BYTE*)opj_malloc(1000);
- if (! l_current_data) {
- opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to decode one tile\n");
- return OPJ_FALSE;
- }
- l_max_data_size = 1000;
-
/*Allocate and initialize some elements of codestrem index if not already done*/
if (!p_j2k->cstr_index->tile_index) {
if (!opj_j2k_allocate_tile_element_cstr_index(p_j2k)) {
- opj_free(l_current_data);
return OPJ_FALSE;
}
}
if (!(opj_stream_read_seek(p_stream,
p_j2k->m_specific_param.m_decoder.m_last_sot_read_pos + 2, p_manager))) {
opj_event_msg(p_manager, EVT_ERROR, "Problem with seek function\n");
- opj_free(l_current_data);
return OPJ_FALSE;
}
} else {
p_j2k->cstr_index->tile_index[l_tile_no_to_dec].tp_index[0].start_pos + 2,
p_manager))) {
opj_event_msg(p_manager, EVT_ERROR, "Problem with seek function\n");
- opj_free(l_current_data);
return OPJ_FALSE;
}
}
&l_go_on,
p_stream,
p_manager)) {
- opj_free(l_current_data);
return OPJ_FALSE;
}
break;
}
- if (l_data_size > l_max_data_size) {
- OPJ_BYTE *l_new_current_data = (OPJ_BYTE *) opj_realloc(l_current_data,
- l_data_size);
- if (! l_new_current_data) {
- opj_free(l_current_data);
- l_current_data = NULL;
- opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to decode tile %d/%d\n",
- l_current_tile_no + 1, p_j2k->m_cp.th * p_j2k->m_cp.tw);
- return OPJ_FALSE;
- }
- l_current_data = l_new_current_data;
- l_max_data_size = l_data_size;
- }
-
- if (! opj_j2k_decode_tile(p_j2k, l_current_tile_no, l_current_data, l_data_size,
+ if (! opj_j2k_decode_tile(p_j2k, l_current_tile_no, NULL, 0,
p_stream, p_manager)) {
- opj_free(l_current_data);
return OPJ_FALSE;
}
opj_event_msg(p_manager, EVT_INFO, "Tile %d/%d has been decoded.\n",
l_current_tile_no + 1, p_j2k->m_cp.th * p_j2k->m_cp.tw);
- if (! opj_j2k_update_image_data(p_j2k->m_tcd, l_current_data,
+ if (! opj_j2k_update_image_data(p_j2k->m_tcd,
p_j2k->m_output_image)) {
- opj_free(l_current_data);
return OPJ_FALSE;
}
+ 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);
if (!(opj_stream_read_seek(p_stream, p_j2k->cstr_index->main_head_end + 2,
p_manager))) {
opj_event_msg(p_manager, EVT_ERROR, "Problem with seek function\n");
- opj_free(l_current_data);
return OPJ_FALSE;
}
break;
}
- opj_free(l_current_data);
-
return OPJ_TRUE;
}
/* Type to use for bit-fields in internal headers */
typedef unsigned int OPJ_BITFIELD;
+#define OPJ_UNUSED(x) (void)x
+
#include "opj_inttypes.h"
#include "opj_clock.h"
#include "opj_malloc.h"
#include "t2.h"
#include "mct.h"
#include "opj_intmath.h"
+#include "sparse_array.h"
#ifdef USE_JPIP
#include "cidx_manager.h"
--- /dev/null
+/*
+ * The copyright in this software is being made available under the 2-clauses
+ * BSD License, included below. This software may be subject to other third
+ * party and contributor rights, including patent rights, and no such rights
+ * are granted under this license.
+ *
+ * Copyright (c) 2017, IntoPix SA <contact@intopix.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "opj_includes.h"
+
+
+struct opj_sparse_array_int32 {
+ OPJ_UINT32 width;
+ OPJ_UINT32 height;
+ OPJ_UINT32 block_width;
+ OPJ_UINT32 block_height;
+ OPJ_UINT32 block_count_hor;
+ OPJ_UINT32 block_count_ver;
+ OPJ_INT32** data_blocks;
+};
+
+opj_sparse_array_int32_t* opj_sparse_array_int32_create(OPJ_UINT32 width,
+ OPJ_UINT32 height,
+ OPJ_UINT32 block_width,
+ OPJ_UINT32 block_height)
+{
+ opj_sparse_array_int32_t* sa;
+
+ if (width == 0 || height == 0 || block_width == 0 || block_height == 0) {
+ return NULL;
+ }
+ if (block_width > ((OPJ_UINT32)~0U) / block_height / sizeof(OPJ_INT32)) {
+ return NULL;
+ }
+
+ sa = opj_calloc(1, sizeof(opj_sparse_array_int32_t));
+ sa->width = width;
+ sa->height = height;
+ sa->block_width = block_width;
+ sa->block_height = block_height;
+ sa->block_count_hor = opj_uint_ceildiv(width, block_width);
+ sa->block_count_ver = opj_uint_ceildiv(height, block_height);
+ if (sa->block_count_hor > ((OPJ_UINT32)~0U) / sa->block_count_ver) {
+ opj_free(sa);
+ return NULL;
+ }
+ sa->data_blocks = opj_calloc(sizeof(OPJ_INT32*),
+ sa->block_count_hor * sa->block_count_ver);
+ if (sa->data_blocks == NULL) {
+ opj_free(sa);
+ return NULL;
+ }
+
+ return sa;
+}
+
+void opj_sparse_array_int32_free(opj_sparse_array_int32_t* sa)
+{
+ if (sa) {
+ OPJ_UINT32 i;
+ for (i = 0; i < sa->block_count_hor * sa->block_count_ver; i++) {
+ if (sa->data_blocks[i]) {
+ opj_free(sa->data_blocks[i]);
+ }
+ }
+ opj_free(sa->data_blocks);
+ opj_free(sa);
+ }
+}
+
+OPJ_BOOL opj_sparse_array_is_region_valid(opj_sparse_array_int32_t* sa,
+ OPJ_UINT32 x0,
+ OPJ_UINT32 y0,
+ OPJ_UINT32 x1,
+ OPJ_UINT32 y1)
+{
+ return !(x0 >= sa->width || x1 <= x0 || x1 > sa->width ||
+ y0 >= sa->height || y1 <= y0 || y1 > sa->height);
+}
+
+static OPJ_BOOL opj_sparse_array_int32_read_or_write(
+ opj_sparse_array_int32_t* sa,
+ OPJ_UINT32 x0,
+ OPJ_UINT32 y0,
+ OPJ_UINT32 x1,
+ OPJ_UINT32 y1,
+ OPJ_INT32* buf,
+ OPJ_UINT32 buf_col_stride,
+ OPJ_UINT32 buf_line_stride,
+ OPJ_BOOL forgiving,
+ OPJ_BOOL is_read_op)
+{
+ OPJ_UINT32 y, block_y;
+ OPJ_UINT32 y_incr = 0;
+ if (!opj_sparse_array_is_region_valid(sa, x0, y0, x1, y1)) {
+ return forgiving;
+ }
+
+ block_y = y0 / sa->block_height;
+ for (y = y0; y < y1; block_y ++, y += y_incr) {
+ OPJ_UINT32 x, block_x;
+ OPJ_UINT32 x_incr = 0;
+ OPJ_UINT32 block_y_offset;
+ y_incr = (y == y0) ? sa->block_height - (y0 % sa->block_height) :
+ sa->block_height;
+ block_y_offset = sa->block_height - y_incr;
+ y_incr = opj_uint_min(y_incr, y1 - y);
+ block_x = x0 / sa->block_width;
+ for (x = x0; x < x1; block_x ++, x += x_incr) {
+ OPJ_UINT32 j;
+ OPJ_UINT32 block_x_offset;
+ OPJ_INT32* src_block;
+ x_incr = (x == x0) ? sa->block_width - (x0 % sa->block_width) : sa->block_width;
+ block_x_offset = sa->block_width - x_incr;
+ x_incr = opj_uint_min(x_incr, x1 - x);
+ src_block = sa->data_blocks[block_y * sa->block_count_hor + block_x];
+ if (is_read_op) {
+ if (src_block == NULL) {
+ for (j = 0; j < y_incr; j++) {
+ if (buf_col_stride == 1) {
+ memset(buf + (y - y0 + j) * buf_line_stride + (x - x0) * buf_col_stride,
+ 0,
+ sizeof(OPJ_INT32) * x_incr);
+ } else {
+ OPJ_UINT32 k;
+ for (k = 0; k < x_incr; k++) {
+ *(buf + (y - y0 + j) * buf_line_stride + (x - x0 + k) * buf_col_stride) = 0;
+ }
+ }
+ }
+ } else {
+ for (j = 0; j < y_incr; j++) {
+ if (buf_col_stride == 1) {
+ memcpy(buf + (y - y0 + j) * buf_line_stride + (x - x0) * buf_col_stride,
+ src_block + (block_y_offset + j) * sa->block_width + block_x_offset,
+ sizeof(OPJ_INT32) * x_incr);
+ } else {
+ OPJ_UINT32 k;
+ for (k = 0; k < x_incr; k++) {
+ *(buf + (y - y0 + j) * buf_line_stride + (x - x0 + k) * buf_col_stride) =
+ *(src_block + (block_y_offset + j) * sa->block_width + block_x_offset + k);
+ }
+ }
+ }
+ }
+ } else {
+ if (src_block == NULL) {
+ src_block = opj_calloc(1,
+ sa->block_width * sa->block_height * sizeof(OPJ_INT32));
+ if (src_block == NULL) {
+ return OPJ_FALSE;
+ }
+ sa->data_blocks[block_y * sa->block_count_hor + block_x] = src_block;
+ }
+
+ for (j = 0; j < y_incr; j++) {
+ if (buf_col_stride == 1) {
+ memcpy(src_block + (block_y_offset + j) * sa->block_width + block_x_offset,
+ buf + (y - y0 + j) * buf_line_stride + (x - x0) * buf_col_stride,
+ sizeof(OPJ_INT32) * x_incr);
+ } else {
+ OPJ_UINT32 k;
+ for (k = 0; k < x_incr; k++) {
+ *(src_block + (block_y_offset + j) * sa->block_width + block_x_offset + k) =
+ *(buf + (y - y0 + j) * buf_line_stride + (x - x0 + k) * buf_col_stride);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return OPJ_TRUE;
+}
+
+OPJ_BOOL opj_sparse_array_int32_read(opj_sparse_array_int32_t* sa,
+ OPJ_UINT32 x0,
+ OPJ_UINT32 y0,
+ OPJ_UINT32 x1,
+ OPJ_UINT32 y1,
+ OPJ_INT32* dest,
+ OPJ_UINT32 dest_col_stride,
+ OPJ_UINT32 dest_line_stride,
+ OPJ_BOOL forgiving)
+{
+ return opj_sparse_array_int32_read_or_write(sa, x0, y0, x1, y1,
+ dest,
+ dest_col_stride,
+ dest_line_stride,
+ forgiving,
+ OPJ_TRUE);
+}
+
+OPJ_BOOL opj_sparse_array_int32_write(opj_sparse_array_int32_t* sa,
+ OPJ_UINT32 x0,
+ OPJ_UINT32 y0,
+ OPJ_UINT32 x1,
+ OPJ_UINT32 y1,
+ const OPJ_INT32* src,
+ OPJ_UINT32 src_col_stride,
+ OPJ_UINT32 src_line_stride,
+ OPJ_BOOL forgiving)
+{
+ return opj_sparse_array_int32_read_or_write(sa, x0, y0, x1, y1,
+ (OPJ_INT32*)src,
+ src_col_stride,
+ src_line_stride,
+ forgiving,
+ OPJ_FALSE);
+}
--- /dev/null
+/*
+ * The copyright in this software is being made available under the 2-clauses
+ * BSD License, included below. This software may be subject to other third
+ * party and contributor rights, including patent rights, and no such rights
+ * are granted under this license.
+ *
+ * Copyright (c) 2017, IntoPix SA <contact@intopix.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "opj_includes.h"
+
+#ifndef OPJ_SPARSE_ARRAY_H
+#define OPJ_SPARSE_ARRAY_H
+/**
+@file sparse_array.h
+@brief Sparse array management
+
+The functions in this file manage sparse arrays. Sparse arrays are arrays with
+potential big dimensions, but with very few samples actually set. Such sparse
+arrays require allocating a low amount of memory, by just allocating memory
+for blocks of the array that are set. The minimum memory allocation unit is a
+a block. There is a trade-off to pick up an appropriate dimension for blocks.
+If it is too big, and pixels set are far from each other, too much memory will
+be used. If blocks are too small, the book-keeping costs of blocks will raise.
+*/
+
+/** @defgroup SPARSE_ARRAY SPARSE ARRAYS - Sparse arrays */
+/*@{*/
+
+/** Opaque type for sparse arrays that contain int32 values */
+typedef struct opj_sparse_array_int32 opj_sparse_array_int32_t;
+
+/** Creates a new sparse array.
+ * @param width total width of the array.
+ * @param height total height of the array
+ * @param block_width width of a block.
+ * @param block_height height of a block.
+ * @return a new sparse array instance, or NULL in case of failure.
+ */
+opj_sparse_array_int32_t* opj_sparse_array_int32_create(OPJ_UINT32 width,
+ OPJ_UINT32 height,
+ OPJ_UINT32 block_width,
+ OPJ_UINT32 block_height);
+
+/** Frees a sparse array.
+ * @param sa sparse array instance.
+ */
+void opj_sparse_array_int32_free(opj_sparse_array_int32_t* sa);
+
+/** Returns whether region bounds are valid (non empty and within array bounds)
+ * @param sa sparse array instance.
+ * @param x0 left x coordinate of the region.
+ * @param y0 top x coordinate of the region.
+ * @param x1 right x coordinate (not included) of the region. Must be greater than x0.
+ * @param y1 bottom y coordinate (not included) of the region. Must be greater than y0.
+ * @return OPJ_TRUE or OPJ_FALSE.
+ */
+OPJ_BOOL opj_sparse_array_is_region_valid(opj_sparse_array_int32_t* sa,
+ OPJ_UINT32 x0,
+ OPJ_UINT32 y0,
+ OPJ_UINT32 x1,
+ OPJ_UINT32 y1);
+
+/** Read the content of a rectangular region of the sparse array into a
+ * user buffer.
+ *
+ * Regions not written with opj_sparse_array_int32_write() are read as 0.
+ *
+ * @param sa sparse array instance.
+ * @param x0 left x coordinate of the region to read in the sparse array.
+ * @param y0 top x coordinate of the region to read in the sparse array.
+ * @param x1 right x coordinate (not included) of the region to read in the sparse array. Must be greater than x0.
+ * @param y1 bottom y coordinate (not included) of the region to read in the sparse array. Must be greater than y0.
+ * @param dest user buffer to fill. Must be at least sizeof(int32) * ( (y1 - y0 - 1) * dest_line_stride + (x1 - x0 - 1) * dest_col_stride + 1) bytes large.
+ * @param dest_col_stride spacing (in elements, not in bytes) in x dimension between consecutive elements of the user buffer.
+ * @param dest_line_stride spacing (in elements, not in bytes) in y dimension between consecutive elements of the user buffer.
+ * @param forgiving if set to TRUE and the region is invalid, OPJ_TRUE will still be returned.
+ * @return OPJ_TRUE in case of success.
+ */
+OPJ_BOOL opj_sparse_array_int32_read(opj_sparse_array_int32_t* sa,
+ OPJ_UINT32 x0,
+ OPJ_UINT32 y0,
+ OPJ_UINT32 x1,
+ OPJ_UINT32 y1,
+ OPJ_INT32* dest,
+ OPJ_UINT32 dest_col_stride,
+ OPJ_UINT32 dest_line_stride,
+ OPJ_BOOL forgiving);
+
+
+/** Write the content of a rectangular region into the sparse array from a
+ * user buffer.
+ *
+ * Blocks intersecting the region are allocated, if not already done.
+ *
+ * @param sa sparse array instance.
+ * @param x0 left x coordinate of the region to write into the sparse array.
+ * @param y0 top x coordinate of the region to write into the sparse array.
+ * @param x1 right x coordinate (not included) of the region to write into the sparse array. Must be greater than x0.
+ * @param y1 bottom y coordinate (not included) of the region to write into the sparse array. Must be greater than y0.
+ * @param src user buffer to fill. Must be at least sizeof(int32) * ( (y1 - y0 - 1) * src_line_stride + (x1 - x0 - 1) * src_col_stride + 1) bytes large.
+ * @param src_col_stride spacing (in elements, not in bytes) in x dimension between consecutive elements of the user buffer.
+ * @param src_line_stride spacing (in elements, not in bytes) in y dimension between consecutive elements of the user buffer.
+ * @param forgiving if set to TRUE and the region is invalid, OPJ_TRUE will still be returned.
+ * @return OPJ_TRUE in case of success.
+ */
+OPJ_BOOL opj_sparse_array_int32_write(opj_sparse_array_int32_t* sa,
+ OPJ_UINT32 x0,
+ OPJ_UINT32 y0,
+ OPJ_UINT32 x1,
+ OPJ_UINT32 y1,
+ const OPJ_INT32* src,
+ OPJ_UINT32 src_col_stride,
+ OPJ_UINT32 src_line_stride,
+ OPJ_BOOL forgiving);
+
+/*@}*/
+
+#endif /* OPJ_SPARSE_ARRAY_H */
\ No newline at end of file
band = job->band;
tilec = job->tilec;
tccp = job->tccp;
- tile_w = (OPJ_UINT32)(tilec->x1 - tilec->x0);
+ tile_w = (OPJ_UINT32)(tilec->resolutions[tilec->minimum_num_resolutions - 1].x1
+ -
+ tilec->resolutions[tilec->minimum_num_resolutions - 1].x0);
if (!*(job->pret)) {
opj_free(job);
y += pres->y1 - pres->y0;
}
- datap = t1->data;
+ datap = cblk->decoded_data ? cblk->decoded_data : t1->data;
cblk_w = t1->w;
cblk_h = t1->h;
}
}
}
- if (tccp->qmfbid == 1) {
+
+ if (cblk->decoded_data) {
+ if (tccp->qmfbid == 1) {
+ for (j = 0; j < cblk_h; ++j) {
+ i = 0;
+ for (; i < (cblk_w & ~(OPJ_UINT32)3U); i += 4U) {
+ OPJ_INT32 tmp0 = datap[(j * cblk_w) + i + 0U];
+ OPJ_INT32 tmp1 = datap[(j * cblk_w) + i + 1U];
+ OPJ_INT32 tmp2 = datap[(j * cblk_w) + i + 2U];
+ OPJ_INT32 tmp3 = datap[(j * cblk_w) + i + 3U];
+ datap[(j * cblk_w) + i + 0U] = tmp0 / 2;
+ datap[(j * cblk_w) + i + 1U] = tmp1 / 2;
+ datap[(j * cblk_w) + i + 2U] = tmp2 / 2;
+ datap[(j * cblk_w) + i + 3U] = tmp3 / 2;
+ }
+ for (; i < cblk_w; ++i) {
+ datap[(j * cblk_w) + i] /= 2;
+ }
+ }
+ } else { /* if (tccp->qmfbid == 0) */
+ for (j = 0; j < cblk_h; ++j) {
+ for (i = 0; i < cblk_w; ++i) {
+ OPJ_FLOAT32 tmp = ((OPJ_FLOAT32)(*datap)) * band->stepsize;
+ memcpy(datap, &tmp, sizeof(tmp));
+ datap++;
+ }
+ }
+ }
+ } else if (tccp->qmfbid == 1) {
OPJ_INT32* OPJ_RESTRICT tiledp = &tilec->data[(OPJ_UINT32)y * tile_w +
(OPJ_UINT32)x];
for (j = 0; j < cblk_h; ++j) {
for (precno = 0; precno < res->pw * res->ph; ++precno) {
opj_tcd_precinct_t* precinct = &band->precincts[precno];
- OPJ_BOOL skip_precinct = OPJ_FALSE;
if (!opj_tcd_is_subband_area_of_interest(tcd,
tilec->compno,
(OPJ_UINT32)precinct->y0,
(OPJ_UINT32)precinct->x1,
(OPJ_UINT32)precinct->y1)) {
- skip_precinct = OPJ_TRUE;
- /* TODO: do a continue here once the below 0 initialization */
- /* of tiledp is removed */
+ continue;
}
for (cblkno = 0; cblkno < precinct->cw * precinct->ch; ++cblkno) {
opj_tcd_cblk_dec_t* cblk = &precinct->cblks.dec[cblkno];
opj_t1_cblk_decode_processing_job_t* job;
- if (skip_precinct ||
- !opj_tcd_is_subband_area_of_interest(tcd,
- tilec->compno,
- resno,
- band->bandno,
- (OPJ_UINT32)cblk->x0,
- (OPJ_UINT32)cblk->y0,
- (OPJ_UINT32)cblk->x1,
- (OPJ_UINT32)cblk->y1)) {
-
- /* TODO: remove this once we don't iterate over */
- /* tile pixels that are not in the subwindow of interest */
- OPJ_UINT32 j;
- OPJ_INT32 x = cblk->x0 - band->x0;
- OPJ_INT32 y = cblk->y0 - band->y0;
- OPJ_INT32* OPJ_RESTRICT tiledp;
- OPJ_UINT32 tile_w = (OPJ_UINT32)(tilec->x1 - tilec->x0);
+ assert(cblk->decoded_data == NULL);
+
+ if (!opj_tcd_is_subband_area_of_interest(tcd,
+ tilec->compno,
+ resno,
+ band->bandno,
+ (OPJ_UINT32)cblk->x0,
+ (OPJ_UINT32)cblk->y0,
+ (OPJ_UINT32)cblk->x1,
+ (OPJ_UINT32)cblk->y1)) {
+ 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 (band->bandno & 1) {
- opj_tcd_resolution_t* pres = &tilec->resolutions[resno - 1];
- x += pres->x1 - pres->x0;
+ if (cblk_w == 0 || cblk_h == 0) {
+ continue;
}
- if (band->bandno & 2) {
- opj_tcd_resolution_t* pres = &tilec->resolutions[resno - 1];
- y += pres->y1 - pres->y0;
- }
-
- tiledp = &tilec->data[(OPJ_UINT32)y * tile_w +
- (OPJ_UINT32)x];
-
- for (j = 0; j < cblk_h; ++j) {
- memset(tiledp + j * tile_w, 0, cblk_w * sizeof(OPJ_INT32));
+ /* Zero-init required */
+ cblk->decoded_data = opj_calloc(1, cblk_w * cblk_h * sizeof(OPJ_INT32));
+ if (cblk->decoded_data == NULL) {
+ if (p_manager_mutex) {
+ opj_mutex_lock(p_manager_mutex);
+ }
+ opj_event_msg(p_manager, EVT_ERROR,
+ "Cannot allocate cblk->decoded_data\n");
+ if (p_manager_mutex) {
+ opj_mutex_unlock(p_manager_mutex);
+ }
+ *pret = OPJ_FALSE;
+ return;
}
- continue;
}
job = (opj_t1_cblk_decode_processing_job_t*) opj_calloc(1,
OPJ_BYTE* cblkdata = NULL;
OPJ_UINT32 cblkdataindex = 0;
OPJ_BYTE type = T1_TYPE_MQ; /* BYPASS mode */
+ OPJ_INT32* original_t1_data = NULL;
mqc->lut_ctxno_zc_orient = lut_ctxno_zc + (orient << 9);
cblkdata = cblk->chunks[0].data;
}
+ /* For subtile decoding, directly decode in the decoded_data buffer of */
+ /* the code-block. Hack t1->data to point to it, and restore it later */
+ if (cblk->decoded_data) {
+ original_t1_data = t1->data;
+ t1->data = cblk->decoded_data;
+ }
+
for (segno = 0; segno < cblk->real_num_segs; ++segno) {
opj_tcd_seg_t *seg = &cblk->segs[segno];
}
}
+ /* Restore original t1->data is needed */
+ if (cblk->decoded_data) {
+ t1->data = original_t1_data;
+ }
+
return OPJ_TRUE;
}
opj_codestream_info_t *p_cstr_info,
opj_event_mgr_t *p_manager);
+
+static OPJ_BOOL opj_tcd_is_whole_tilecomp_decoding(opj_tcd_t *tcd,
+ OPJ_UINT32 compno);
+
/* ----------------------------------------------------------------------- */
/**
((l_tilec->data_size_needed > l_tilec->data_size) &&
(l_tilec->ownsData == OPJ_FALSE))) {
l_tilec->data = (OPJ_INT32 *) opj_image_data_alloc(l_tilec->data_size_needed);
- if (! l_tilec->data) {
+ if (!l_tilec->data && l_tilec->data_size_needed != 0) {
return OPJ_FALSE;
}
/*fprintf(stderr, "tAllocate data of tilec (int): %d x OPJ_UINT32n",l_data_size);*/
l_tilec->compno = compno;
/*fprintf(stderr, "\tTile compo border = %d,%d,%d,%d\n", l_tilec->x0, l_tilec->y0,l_tilec->x1,l_tilec->y1);*/
- /* compute l_data_size with overflow check */
- l_data_size = (OPJ_UINT32)(l_tilec->x1 - l_tilec->x0);
- /* issue 733, l_data_size == 0U, probably something wrong should be checked before getting here */
- if ((l_data_size > 0U) &&
- ((((OPJ_UINT32) - 1) / l_data_size) < (OPJ_UINT32)(l_tilec->y1 -
- l_tilec->y0))) {
- opj_event_msg(manager, EVT_ERROR, "Not enough memory for tile data\n");
- return OPJ_FALSE;
- }
- l_data_size = l_data_size * (OPJ_UINT32)(l_tilec->y1 - l_tilec->y0);
-
- if ((((OPJ_UINT32) - 1) / (OPJ_UINT32)sizeof(OPJ_UINT32)) < l_data_size) {
- opj_event_msg(manager, EVT_ERROR, "Not enough memory for tile data\n");
- return OPJ_FALSE;
- }
- l_data_size = l_data_size * (OPJ_UINT32)sizeof(OPJ_UINT32);
l_tilec->numresolutions = l_tccp->numresolutions;
if (l_tccp->numresolutions < l_cp->m_specific_param.m_dec.m_reduce) {
l_tilec->minimum_num_resolutions = 1;
l_cp->m_specific_param.m_dec.m_reduce;
}
- l_tilec->data_size_needed = l_data_size;
- if (p_tcd->m_is_decoder && !opj_alloc_tile_component_data(l_tilec)) {
- opj_event_msg(manager, EVT_ERROR, "Not enough memory for tile data\n");
- return OPJ_FALSE;
+ if (isEncoder) {
+ /* compute l_data_size with overflow check */
+ l_data_size = (OPJ_UINT32)(l_tilec->x1 - l_tilec->x0);
+ /* issue 733, l_data_size == 0U, probably something wrong should be checked before getting here */
+ if ((l_data_size > 0U) &&
+ ((((OPJ_UINT32) - 1) / l_data_size) < (OPJ_UINT32)(l_tilec->y1 -
+ l_tilec->y0))) {
+ opj_event_msg(manager, EVT_ERROR, "Not enough memory for tile data\n");
+ return OPJ_FALSE;
+ }
+ l_data_size = l_data_size * (OPJ_UINT32)(l_tilec->y1 - l_tilec->y0);
+
+ if ((((OPJ_UINT32) - 1) / (OPJ_UINT32)sizeof(OPJ_UINT32)) < l_data_size) {
+ opj_event_msg(manager, EVT_ERROR, "Not enough memory for tile data\n");
+ return OPJ_FALSE;
+ }
+ l_data_size = l_data_size * (OPJ_UINT32)sizeof(OPJ_UINT32);
+
+ l_tilec->data_size_needed = l_data_size;
}
l_data_size = l_tilec->numresolutions * (OPJ_UINT32)sizeof(
opj_tcd_resolution_t);
+ opj_aligned_free(l_tilec->data_win);
+ l_tilec->data_win = NULL;
+ l_tilec->win_x0 = 0;
+ l_tilec->win_y0 = 0;
+ l_tilec->win_x1 = 0;
+ l_tilec->win_y1 = 0;
+
if (l_tilec->resolutions == 00) {
l_tilec->resolutions = (opj_tcd_resolution_t *) opj_malloc(l_data_size);
if (! l_tilec->resolutions) {
l_res->y0 = opj_int_ceildivpow2(l_tilec->y0, (OPJ_INT32)l_level_no);
l_res->x1 = opj_int_ceildivpow2(l_tilec->x1, (OPJ_INT32)l_level_no);
l_res->y1 = opj_int_ceildivpow2(l_tilec->y1, (OPJ_INT32)l_level_no);
+
+ if (!isEncoder && resno + 1 == l_tilec->minimum_num_resolutions) {
+ /* compute l_data_size with overflow check */
+ OPJ_UINT32 res_w = (OPJ_UINT32)(l_res->x1 - l_res->x0);
+ OPJ_UINT32 res_h = (OPJ_UINT32)(l_res->y1 - l_res->y0);
+
+ /* issue 733, l_data_size == 0U, probably something wrong should be checked before getting here */
+ if (res_h > 0 && res_h > (((OPJ_UINT32) - 1) / res_h)) {
+ opj_event_msg(manager, EVT_ERROR, "Not enough memory for tile data\n");
+ return OPJ_FALSE;
+ }
+ l_data_size = res_w * res_h;
+
+ if ((((OPJ_UINT32) - 1) / (OPJ_UINT32)sizeof(OPJ_UINT32)) < l_data_size) {
+ opj_event_msg(manager, EVT_ERROR, "Not enough memory for tile data\n");
+ return OPJ_FALSE;
+ }
+ l_data_size *= (OPJ_UINT32)sizeof(OPJ_UINT32);
+
+ l_tilec->data_size_needed = l_data_size;
+ }
+
/*fprintf(stderr, "\t\t\tres_x0= %d, res_y0 =%d, res_x1=%d, res_y1=%d\n", l_res->x0, l_res->y0, l_res->x1, l_res->y1);*/
/* p. 35, table A-23, ISO/IEC FDIS154444-1 : 2000 (18 august 2000) */
l_pdx = l_tccp->prcw[resno];
OPJ_UINT32 l_numchunksalloc = p_code_block->numchunksalloc;
OPJ_UINT32 i;
+ opj_free(p_code_block->decoded_data);
+ p_code_block->decoded_data = 00;
+
memset(p_code_block, 0, sizeof(opj_tcd_cblk_dec_t));
p_code_block->segs = l_segs;
p_code_block->m_current_max_segs = l_current_max_segs;
return OPJ_TRUE;
}
-OPJ_UINT32 opj_tcd_get_decoded_tile_size(opj_tcd_t *p_tcd)
+OPJ_UINT32 opj_tcd_get_decoded_tile_size(opj_tcd_t *p_tcd,
+ OPJ_BOOL take_into_account_partial_decoding)
{
OPJ_UINT32 i;
OPJ_UINT32 l_data_size = 0;
}
l_res = l_tile_comp->resolutions + l_tile_comp->minimum_num_resolutions - 1;
- l_temp = (OPJ_UINT32)((l_res->x1 - l_res->x0) * (l_res->y1 -
- l_res->y0)); /* x1*y1 can't overflow */
+ if (take_into_account_partial_decoding && !p_tcd->whole_tile_decoding) {
+ l_temp = (l_res->win_x1 - l_res->win_x0) *
+ (l_res->win_y1 - l_res->win_y0);
+ } else {
+ l_temp = (OPJ_UINT32)((l_res->x1 - l_res->x0) * (l_res->y1 -
+ l_res->y0)); /* x1*y1 can't overflow */
+ }
if (l_size_comp && UINT_MAX / l_size_comp < l_temp) {
return UINT_MAX;
}
}
OPJ_BOOL opj_tcd_decode_tile(opj_tcd_t *p_tcd,
- OPJ_UINT32 decoded_x0,
- OPJ_UINT32 decoded_y0,
- OPJ_UINT32 decoded_x1,
- OPJ_UINT32 decoded_y1,
+ OPJ_UINT32 win_x0,
+ OPJ_UINT32 win_y0,
+ OPJ_UINT32 win_x1,
+ OPJ_UINT32 win_y1,
OPJ_BYTE *p_src,
OPJ_UINT32 p_max_length,
OPJ_UINT32 p_tile_no,
)
{
OPJ_UINT32 l_data_read;
+ OPJ_UINT32 compno;
+
p_tcd->tcd_tileno = p_tile_no;
p_tcd->tcp = &(p_tcd->cp->tcps[p_tile_no]);
- p_tcd->decoded_x0 = decoded_x0;
- p_tcd->decoded_y0 = decoded_y0;
- p_tcd->decoded_x1 = decoded_x1;
- p_tcd->decoded_y1 = decoded_y1;
+ p_tcd->win_x0 = win_x0;
+ p_tcd->win_y0 = win_y0;
+ p_tcd->win_x1 = win_x1;
+ p_tcd->win_y1 = win_y1;
+ p_tcd->whole_tile_decoding = OPJ_TRUE;
+
+ for (compno = 0; compno < p_tcd->image->numcomps; compno++) {
+ if (!opj_tcd_is_whole_tilecomp_decoding(p_tcd, compno)) {
+ p_tcd->whole_tile_decoding = OPJ_FALSE;
+ break;
+ }
+ }
+
+ if (p_tcd->whole_tile_decoding) {
+ for (compno = 0; compno < p_tcd->image->numcomps; compno++) {
+ if (!opj_alloc_tile_component_data(&(p_tcd->tcd_image->tiles->comps[compno]))) {
+ opj_event_msg(p_manager, EVT_ERROR, "Not enough memory for tile data\n");
+ return OPJ_FALSE;
+ }
+ }
+ } else {
+ /* Compute restricted tile-component and tile-resolution coordinates */
+ /* of the window of interest, but defer the memory allocation until */
+ /* we know the resno_decoded */
+ for (compno = 0; compno < p_tcd->image->numcomps; compno++) {
+ OPJ_UINT32 resno;
+ opj_tcd_tilecomp_t* tilec = &(p_tcd->tcd_image->tiles->comps[compno]);
+ opj_image_comp_t* image_comp = &(p_tcd->image->comps[compno]);
+ /* Compute the intersection of the area of interest, expressed in tile coordinates */
+ /* with the tile coordinates */
+ tilec->win_x0 = opj_uint_max(
+ (OPJ_UINT32)tilec->x0,
+ opj_uint_ceildiv(p_tcd->win_x0, image_comp->dx));
+ tilec->win_y0 = opj_uint_max(
+ (OPJ_UINT32)tilec->y0,
+ opj_uint_ceildiv(p_tcd->win_y0, image_comp->dy));
+ tilec->win_x1 = opj_uint_min(
+ (OPJ_UINT32)tilec->x1,
+ opj_uint_ceildiv(p_tcd->win_x1, image_comp->dx));
+ tilec->win_y1 = opj_uint_min(
+ (OPJ_UINT32)tilec->y1,
+ opj_uint_ceildiv(p_tcd->win_y1, image_comp->dy));
+
+ for (resno = 0; resno < tilec->numresolutions; ++resno) {
+ opj_tcd_resolution_t *res = tilec->resolutions + resno;
+ res->win_x0 = opj_uint_ceildivpow2(tilec->win_x0,
+ tilec->numresolutions - 1 - resno);
+ res->win_y0 = opj_uint_ceildivpow2(tilec->win_y0,
+ tilec->numresolutions - 1 - resno);
+ res->win_x1 = opj_uint_ceildivpow2(tilec->win_x1,
+ tilec->numresolutions - 1 - resno);
+ res->win_y1 = opj_uint_ceildivpow2(tilec->win_y1,
+ tilec->numresolutions - 1 - resno);
+ }
+ }
+ }
#ifdef TODO_MSD /* FIXME */
/* INDEX >> */
}
/* FIXME _ProfStop(PGROUP_T1); */
+
+ /* For subtile decoding, now we know the resno_decoded, we can allocate */
+ /* the tile data buffer */
+ if (!p_tcd->whole_tile_decoding) {
+ for (compno = 0; compno < p_tcd->image->numcomps; compno++) {
+ opj_tcd_tilecomp_t* tilec = &(p_tcd->tcd_image->tiles->comps[compno]);
+ opj_image_comp_t* image_comp = &(p_tcd->image->comps[compno]);
+ opj_tcd_resolution_t *res = tilec->resolutions + image_comp->resno_decoded;
+ OPJ_UINT32 w = res->win_x1 - res->win_x0;
+ OPJ_UINT32 h = res->win_y1 - res->win_y0;
+ OPJ_UINT32 l_data_size;
+
+ opj_aligned_free(tilec->data_win);
+ tilec->data_win = NULL;
+
+ if (w > 0 && h > 0) {
+ if (w > ((OPJ_UINT32) - 1) / h) {
+ opj_event_msg(p_manager, EVT_ERROR, "Not enough memory for tile data\n");
+ return OPJ_FALSE;
+ }
+ l_data_size = w * h;
+ if (l_data_size > ((OPJ_UINT32) - 1) / sizeof(OPJ_INT32)) {
+ opj_event_msg(p_manager, EVT_ERROR, "Not enough memory for tile data\n");
+ return OPJ_FALSE;
+ }
+ l_data_size *= (OPJ_UINT32)sizeof(OPJ_INT32);
+
+ tilec->data_win = opj_aligned_malloc(l_data_size);
+ if (tilec->data_win == NULL) {
+ opj_event_msg(p_manager, EVT_ERROR, "Not enough memory for tile data\n");
+ return OPJ_FALSE;
+ }
+ }
+ }
+ }
+
/*----------------DWT---------------------*/
/* FIXME _ProfStart(PGROUP_DWT); */
OPJ_UINT32 l_size_comp, l_remaining;
OPJ_UINT32 l_stride, l_width, l_height;
- l_data_size = opj_tcd_get_decoded_tile_size(p_tcd);
+ l_data_size = opj_tcd_get_decoded_tile_size(p_tcd, OPJ_TRUE);
if (l_data_size == UINT_MAX || l_data_size > p_dest_length) {
return OPJ_FALSE;
}
l_img_comp = p_tcd->image->comps;
for (i = 0; i < p_tcd->image->numcomps; ++i) {
+ const OPJ_INT32* l_src_data;
l_size_comp = l_img_comp->prec >> 3; /*(/ 8)*/
l_remaining = l_img_comp->prec & 7; /* (%8) */
l_res = l_tilec->resolutions + l_img_comp->resno_decoded;
- l_width = (OPJ_UINT32)(l_res->x1 - l_res->x0);
- l_height = (OPJ_UINT32)(l_res->y1 - l_res->y0);
- l_stride = (OPJ_UINT32)(l_tilec->x1 - l_tilec->x0) - l_width;
+ if (p_tcd->whole_tile_decoding) {
+ l_width = (OPJ_UINT32)(l_res->x1 - l_res->x0);
+ l_height = (OPJ_UINT32)(l_res->y1 - l_res->y0);
+ l_stride = (OPJ_UINT32)(l_tilec->resolutions[l_tilec->minimum_num_resolutions -
+ 1].x1 -
+ l_tilec->resolutions[l_tilec->minimum_num_resolutions - 1].x0) - l_width;
+ l_src_data = l_tilec->data;
+ } else {
+ l_width = l_res->win_x1 - l_res->win_x0;
+ l_height = l_res->win_y1 - l_res->win_y0;
+ l_stride = 0;
+ l_src_data = l_tilec->data_win;
+ }
if (l_remaining) {
++l_size_comp;
switch (l_size_comp) {
case 1: {
OPJ_CHAR * l_dest_ptr = (OPJ_CHAR *) p_dest;
- const OPJ_INT32 * l_src_ptr = l_tilec->data;
+ const OPJ_INT32 * l_src_ptr = l_src_data;
if (l_img_comp->sgnd) {
for (j = 0; j < l_height; ++j) {
}
break;
case 2: {
- const OPJ_INT32 * l_src_ptr = l_tilec->data;
+ const OPJ_INT32 * l_src_ptr = l_src_data;
OPJ_INT16 * l_dest_ptr = (OPJ_INT16 *) p_dest;
if (l_img_comp->sgnd) {
break;
case 4: {
OPJ_INT32 * l_dest_ptr = (OPJ_INT32 *) p_dest;
- OPJ_INT32 * l_src_ptr = l_tilec->data;
+ const OPJ_INT32 * l_src_ptr = l_src_data;
for (j = 0; j < l_height; ++j) {
memcpy(l_dest_ptr, l_src_ptr, l_width * sizeof(OPJ_INT32));
l_tile_comp->data_size = 0;
l_tile_comp->data_size_needed = 0;
}
+
+ opj_aligned_free(l_tile_comp->data_win);
+
++l_tile_comp;
}
opj_image_comp_t * l_img_comp = p_tcd->image->comps;
for (compno = 0; compno < l_tile->numcomps; compno++) {
- /*
- if (tcd->cp->reduce != 0) {
- tcd->image->comps[compno].resno_decoded =
- tile->comps[compno].numresolutions - tcd->cp->reduce - 1;
- if (tcd->image->comps[compno].resno_decoded < 0)
- {
- return false;
- }
- }
- numres2decode = tcd->image->comps[compno].resno_decoded + 1;
- if(numres2decode > 0){
- */
if (l_tccp->qmfbid == 1) {
if (! opj_dwt_decode(p_tcd, l_tile_comp,
return OPJ_TRUE;
}
+
static OPJ_BOOL opj_tcd_mct_decode(opj_tcd_t *p_tcd, opj_event_mgr_t *p_manager)
{
opj_tcd_tile_t * l_tile = p_tcd->tcd_image->tiles;
return OPJ_TRUE;
}
- l_samples = (OPJ_UINT32)((l_tile_comp->x1 - l_tile_comp->x0) *
- (l_tile_comp->y1 - l_tile_comp->y0));
+ if (p_tcd->whole_tile_decoding) {
+ /* A bit inefficient: we process more data than needed if */
+ /* resno_decoded < l_tile_comp->minimum_num_resolutions-1, */
+ /* but we would need to take into account a stride then */
+ l_samples = (OPJ_UINT32)((
+ l_tile_comp->resolutions[l_tile_comp->minimum_num_resolutions - 1].x1 -
+ l_tile_comp->resolutions[l_tile_comp->minimum_num_resolutions - 1].x0) *
+ (l_tile_comp->resolutions[l_tile_comp->minimum_num_resolutions - 1].y1 -
+ l_tile_comp->resolutions[l_tile_comp->minimum_num_resolutions - 1].y0));
+ } else {
+ opj_tcd_resolution_t* l_res;
+ l_res = l_tile_comp->resolutions + p_tcd->image->comps[0].resno_decoded;
+ l_samples = (l_res->win_x1 - l_res->win_x0) *
+ (l_res->win_y1 - l_res->win_y0);
+ }
if (l_tile->numcomps >= 3) {
+ opj_tcd_resolution_t* res_comp0 = l_tile->comps[0].resolutions +
+ p_tcd->image->comps[0].resno_decoded;
+ opj_tcd_resolution_t* res_comp1 = l_tile->comps[1].resolutions +
+ p_tcd->image->comps[1].resno_decoded;
+ opj_tcd_resolution_t* res_comp2 = l_tile->comps[2].resolutions +
+ p_tcd->image->comps[2].resno_decoded;
+ OPJ_INT32 l_res_samples = (OPJ_INT32)(res_comp0->x1 - res_comp0->x0) *
+ (res_comp0->y1 - res_comp0->y0);
/* testcase 1336.pdf.asan.47.376 */
- if ((l_tile->comps[0].x1 - l_tile->comps[0].x0) * (l_tile->comps[0].y1 -
- l_tile->comps[0].y0) < (OPJ_INT32)l_samples ||
- (l_tile->comps[1].x1 - l_tile->comps[1].x0) * (l_tile->comps[1].y1 -
- l_tile->comps[1].y0) < (OPJ_INT32)l_samples ||
- (l_tile->comps[2].x1 - l_tile->comps[2].x0) * (l_tile->comps[2].y1 -
- l_tile->comps[2].y0) < (OPJ_INT32)l_samples) {
+ if (p_tcd->image->comps[0].resno_decoded !=
+ p_tcd->image->comps[1].resno_decoded ||
+ p_tcd->image->comps[0].resno_decoded !=
+ p_tcd->image->comps[2].resno_decoded ||
+ (res_comp1->x1 - res_comp1->x0) * (res_comp1->y1 -
+ res_comp1->y0) != l_res_samples ||
+ (res_comp2->x1 - res_comp2->x0) * (res_comp2->y1 -
+ res_comp2->y0) != l_res_samples) {
opj_event_msg(p_manager, EVT_ERROR,
"Tiles don't all have the same dimension. Skip the MCT step.\n");
return OPJ_FALSE;
}
for (i = 0; i < l_tile->numcomps; ++i) {
- l_data[i] = (OPJ_BYTE*) l_tile_comp->data;
+ if (p_tcd->whole_tile_decoding) {
+ l_data[i] = (OPJ_BYTE*) l_tile_comp->data;
+ } else {
+ l_data[i] = (OPJ_BYTE*) l_tile_comp->data_win;
+ }
++l_tile_comp;
}
opj_free(l_data);
} else {
if (l_tcp->tccps->qmfbid == 1) {
- opj_mct_decode(l_tile->comps[0].data,
- l_tile->comps[1].data,
- l_tile->comps[2].data,
- l_samples);
+ if (p_tcd->whole_tile_decoding) {
+ opj_mct_decode(l_tile->comps[0].data,
+ l_tile->comps[1].data,
+ l_tile->comps[2].data,
+ l_samples);
+ } else {
+ opj_mct_decode(l_tile->comps[0].data_win,
+ l_tile->comps[1].data_win,
+ l_tile->comps[2].data_win,
+ l_samples);
+ }
} else {
- opj_mct_decode_real((OPJ_FLOAT32*)l_tile->comps[0].data,
- (OPJ_FLOAT32*)l_tile->comps[1].data,
- (OPJ_FLOAT32*)l_tile->comps[2].data,
- l_samples);
+ if (p_tcd->whole_tile_decoding) {
+ opj_mct_decode_real((OPJ_FLOAT32*)l_tile->comps[0].data,
+ (OPJ_FLOAT32*)l_tile->comps[1].data,
+ (OPJ_FLOAT32*)l_tile->comps[2].data,
+ l_samples);
+ } else {
+ opj_mct_decode_real((OPJ_FLOAT32*)l_tile->comps[0].data_win,
+ (OPJ_FLOAT32*)l_tile->comps[1].data_win,
+ (OPJ_FLOAT32*)l_tile->comps[2].data_win,
+ l_samples);
+ }
}
}
} else {
for (compno = 0; compno < l_tile->numcomps; compno++) {
l_res = l_tile_comp->resolutions + l_img_comp->resno_decoded;
- l_width = (OPJ_UINT32)(l_res->x1 - l_res->x0);
- l_height = (OPJ_UINT32)(l_res->y1 - l_res->y0);
- l_stride = (OPJ_UINT32)(l_tile_comp->x1 - l_tile_comp->x0) - l_width;
- assert(l_height == 0 ||
- l_width + l_stride <= l_tile_comp->data_size / l_height); /*MUPDF*/
+ if (!p_tcd->whole_tile_decoding) {
+ l_width = l_res->win_x1 - l_res->win_x0;
+ l_height = l_res->win_y1 - l_res->win_y0;
+ l_stride = 0;
+ l_current_ptr = l_tile_comp->data_win;
+ } else {
+ l_width = (OPJ_UINT32)(l_res->x1 - l_res->x0);
+ l_height = (OPJ_UINT32)(l_res->y1 - l_res->y0);
+ l_stride = (OPJ_UINT32)(
+ l_tile_comp->resolutions[l_tile_comp->minimum_num_resolutions - 1].x1 -
+ l_tile_comp->resolutions[l_tile_comp->minimum_num_resolutions - 1].x0)
+ - l_width;
+ l_current_ptr = l_tile_comp->data;
+
+ assert(l_height == 0 ||
+ l_width + l_stride <= l_tile_comp->data_size / l_height); /*MUPDF*/
+ }
if (l_img_comp->sgnd) {
l_min = -(1 << (l_img_comp->prec - 1));
l_max = (OPJ_INT32)((1U << l_img_comp->prec) - 1);
}
- l_current_ptr = l_tile_comp->data;
if (l_tccp->qmfbid == 1) {
for (j = 0; j < l_height; ++j) {
l_code_block->chunks = 00;
}
+ opj_free(l_code_block->decoded_data);
+ l_code_block->decoded_data = NULL;
+
++l_code_block;
}
/* with the tile coordinates */
OPJ_UINT32 tcx0 = opj_uint_max(
(OPJ_UINT32)tilec->x0,
- opj_uint_ceildiv(tcd->decoded_x0, image_comp->dx));
+ opj_uint_ceildiv(tcd->win_x0, image_comp->dx));
OPJ_UINT32 tcy0 = opj_uint_max(
(OPJ_UINT32)tilec->y0,
- opj_uint_ceildiv(tcd->decoded_y0, image_comp->dy));
+ opj_uint_ceildiv(tcd->win_y0, image_comp->dy));
OPJ_UINT32 tcx1 = opj_uint_min(
(OPJ_UINT32)tilec->x1,
- opj_uint_ceildiv(tcd->decoded_x1, image_comp->dx));
+ opj_uint_ceildiv(tcd->win_x1, image_comp->dx));
OPJ_UINT32 tcy1 = opj_uint_min(
(OPJ_UINT32)tilec->y1,
- opj_uint_ceildiv(tcd->decoded_y1, image_comp->dy));
+ opj_uint_ceildiv(tcd->win_y1, image_comp->dy));
/* Compute number of decomposition for this band. See table F-1 */
OPJ_UINT32 nb = (resno == 0) ?
tilec->numresolutions - 1 :
#endif
return intersects;
}
+
+/** Returns whether a tile componenent is fully decoded, taking into account
+ * p_tcd->win_* members.
+ *
+ * @param p_tcd TCD handle.
+ * @param compno Component number
+ * @return OPJ_TRUE whether the tile componenent is fully decoded
+ */
+static OPJ_BOOL opj_tcd_is_whole_tilecomp_decoding(opj_tcd_t *p_tcd,
+ OPJ_UINT32 compno)
+{
+ opj_tcd_tilecomp_t* tilec = &(p_tcd->tcd_image->tiles->comps[compno]);
+ opj_image_comp_t* image_comp = &(p_tcd->image->comps[compno]);
+ /* Compute the intersection of the area of interest, expressed in tile coordinates */
+ /* with the tile coordinates */
+ OPJ_UINT32 tcx0 = opj_uint_max(
+ (OPJ_UINT32)tilec->x0,
+ opj_uint_ceildiv(p_tcd->win_x0, image_comp->dx));
+ OPJ_UINT32 tcy0 = opj_uint_max(
+ (OPJ_UINT32)tilec->y0,
+ opj_uint_ceildiv(p_tcd->win_y0, image_comp->dy));
+ OPJ_UINT32 tcx1 = opj_uint_min(
+ (OPJ_UINT32)tilec->x1,
+ opj_uint_ceildiv(p_tcd->win_x1, image_comp->dx));
+ OPJ_UINT32 tcy1 = opj_uint_min(
+ (OPJ_UINT32)tilec->y1,
+ opj_uint_ceildiv(p_tcd->win_y1, image_comp->dy));
+
+ OPJ_UINT32 shift = tilec->numresolutions - tilec->minimum_num_resolutions;
+ /* Tolerate small margin within the reduced resolution factor to consider if */
+ /* the whole tile path must be taken */
+ return (tcx0 >= (OPJ_UINT32)tilec->x0 &&
+ tcy0 >= (OPJ_UINT32)tilec->y0 &&
+ tcx1 <= (OPJ_UINT32)tilec->x1 &&
+ tcy1 <= (OPJ_UINT32)tilec->y1 &&
+ (shift >= 32 ||
+ (((tcx0 - (OPJ_UINT32)tilec->x0) >> shift) == 0 &&
+ ((tcy0 - (OPJ_UINT32)tilec->y0) >> shift) == 0 &&
+ (((OPJ_UINT32)tilec->x1 - tcx1) >> shift) == 0 &&
+ (((OPJ_UINT32)tilec->y1 - tcy1) >> shift) == 0)));
+}
OPJ_UINT32 m_current_max_segs; /* allocated number of segs[] items */
OPJ_UINT32 numchunks; /* Number of valid chunks items */
OPJ_UINT32 numchunksalloc; /* Number of chunks item allocated */
+ /* Decoded code-block. Only used for subtile decoding. Otherwise tilec->data is directly updated */
+ OPJ_INT32* decoded_data;
} opj_tcd_cblk_dec_t;
/** Precinct structure */
OPJ_UINT32 numbands;
/* subband information */
opj_tcd_band_t bands[3];
+
+ /* dimension of the resolution limited to window of interest. Only valid if tcd->whole_tile_decoding is set */
+ OPJ_UINT32 win_x0;
+ OPJ_UINT32 win_y0;
+ OPJ_UINT32 win_x1;
+ OPJ_UINT32 win_y1;
} opj_tcd_resolution_t;
/** Tile-component structure */
opj_tcd_resolution_t *resolutions;
/* size of data for resolutions (in bytes) */
OPJ_UINT32 resolutions_size;
- /* data of the component */
+
+ /* data of the component. For decoding, only valid if tcd->whole_tile_decoding is set (so exclusive of data_win member) */
OPJ_INT32 *data;
/* if true, then need to free after usage, otherwise do not free */
OPJ_BOOL ownsData;
OPJ_UINT32 data_size_needed;
/* size of the data of the component */
OPJ_UINT32 data_size;
+
+ /** data of the component limited to window of interest. Only valid for decoding and if tcd->whole_tile_decoding is NOT set (so exclusive of data member) */
+ OPJ_INT32 *data_win;
+ /* dimension of the component limited to window of interest. Only valid for decoding and if tcd->whole_tile_decoding is NOT set */
+ OPJ_UINT32 win_x0;
+ OPJ_UINT32 win_y0;
+ OPJ_UINT32 win_x1;
+ OPJ_UINT32 win_y1;
+
/* add fixed_quality */
OPJ_INT32 numpix;
} opj_tcd_tilecomp_t;
/** Thread pool */
opj_thread_pool_t* thread_pool;
/** Coordinates of the window of interest, in grid reference space */
- OPJ_UINT32 decoded_x0;
- OPJ_UINT32 decoded_y0;
- OPJ_UINT32 decoded_x1;
- OPJ_UINT32 decoded_y1;
+ OPJ_UINT32 win_x0;
+ OPJ_UINT32 win_y0;
+ OPJ_UINT32 win_x1;
+ OPJ_UINT32 win_y1;
+ /** Only valid for decoding. Whether the whole tile is decoded, or just the region in win_x0/win_y0/win_x1/win_y1 */
+ OPJ_BOOL whole_tile_decoding;
} opj_tcd_t;
/** @name Exported functions */
/**
* Gets the maximum tile size that will be taken by the tile once decoded.
*/
-OPJ_UINT32 opj_tcd_get_decoded_tile_size(opj_tcd_t *p_tcd);
+OPJ_UINT32 opj_tcd_get_decoded_tile_size(opj_tcd_t *p_tcd,
+ OPJ_BOOL take_into_account_partial_decoding);
/**
* Encodes a tile from the raw image into the given buffer.
/**
Decode a tile from a buffer into a raw image
@param tcd TCD handle
-@param decoded_x0 Upper left x of region to decode (in grid coordinates)
-@param decoded_y0 Upper left y of region to decode (in grid coordinates)
-@param decoded_x1 Lower right x of region to decode (in grid coordinates)
-@param decoded_y1 Lower right y of region to decode (in grid coordinates)
+@param win_x0 Upper left x of region to decode (in grid coordinates)
+@param win_y0 Upper left y of region to decode (in grid coordinates)
+@param win_x1 Lower right x of region to decode (in grid coordinates)
+@param win_y1 Lower right y of region to decode (in grid coordinates)
@param src Source buffer
@param len Length of source buffer
@param tileno Number that identifies one of the tiles to be decoded
@param manager the event manager.
*/
OPJ_BOOL opj_tcd_decode_tile(opj_tcd_t *tcd,
- OPJ_UINT32 decoded_x0,
- OPJ_UINT32 decoded_y0,
- OPJ_UINT32 decoded_x1,
- OPJ_UINT32 decoded_y1,
+ OPJ_UINT32 win_x0,
+ OPJ_UINT32 win_y0,
+ OPJ_UINT32 win_x1,
+ OPJ_UINT32 win_y1,
OPJ_BYTE *src,
OPJ_UINT32 len,
OPJ_UINT32 tileno,
/** Returns whether a sub-band region contributes to the area of interest
- * tcd->decoded_x0,tcd->decoded_y0,tcd->decoded_x1,tcd->decoded_y1.
+ * tcd->win_x0,tcd->win_y0,tcd->win_x1,tcd->win_y1.
*
* @param tcd TCD handle.
* @param compno Component number
OPJ_UINT32 x1,
OPJ_UINT32 y1);
-
/* ----------------------------------------------------------------------- */
/*@}*/
--- /dev/null
+/*
+ * The copyright in this software is being made available under the 2-clauses
+ * BSD License, included below. This software may be subject to other third
+ * party and contributor rights, including patent rights, and no such rights
+ * are granted under this license.
+ *
+ * Copyright (c) 2017, IntoPix SA <contact@intopix.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "opj_includes.h"
+
+int main()
+{
+ OPJ_UINT32 i, j, w, h;
+ OPJ_INT32 buffer[ 99 * 101 ];
+ OPJ_BOOL ret;
+ opj_sparse_array_int32_t* sa;
+
+ sa = opj_sparse_array_int32_create(0, 1, 1, 1);
+ assert(sa == NULL);
+ opj_sparse_array_int32_free(sa);
+
+ sa = opj_sparse_array_int32_create(1, 0, 1, 1);
+ assert(sa == NULL);
+
+ sa = opj_sparse_array_int32_create(1, 1, 0, 1);
+ assert(sa == NULL);
+
+ sa = opj_sparse_array_int32_create(1, 1, 1, 0);
+ assert(sa == NULL);
+
+ sa = opj_sparse_array_int32_create(99, 101, ~0U, ~0U);
+ assert(sa == NULL);
+
+ sa = opj_sparse_array_int32_create(99, 101, 15, 17);
+ opj_sparse_array_int32_free(sa);
+
+ sa = opj_sparse_array_int32_create(99, 101, 15, 17);
+ ret = opj_sparse_array_int32_read(sa, 0, 0, 0, 1, buffer, 1, 1, OPJ_FALSE);
+ assert(!ret);
+ ret = opj_sparse_array_int32_read(sa, 0, 0, 1, 0, buffer, 1, 1, OPJ_FALSE);
+ assert(!ret);
+ ret = opj_sparse_array_int32_read(sa, 0, 0, 100, 1, buffer, 1, 1, OPJ_FALSE);
+ assert(!ret);
+ ret = opj_sparse_array_int32_read(sa, 0, 0, 1, 102, buffer, 1, 1, OPJ_FALSE);
+ assert(!ret);
+ ret = opj_sparse_array_int32_read(sa, 1, 0, 0, 1, buffer, 1, 1, OPJ_FALSE);
+ assert(!ret);
+ ret = opj_sparse_array_int32_read(sa, 0, 1, 1, 0, buffer, 1, 1, OPJ_FALSE);
+ assert(!ret);
+ ret = opj_sparse_array_int32_read(sa, 99, 101, 99, 101, buffer, 1, 1,
+ OPJ_FALSE);
+ assert(!ret);
+
+ buffer[0] = 1;
+ ret = opj_sparse_array_int32_read(sa, 0, 0, 1, 1, buffer, 1, 1, OPJ_FALSE);
+ assert(ret);
+ assert(buffer[0] == 0);
+
+ memset(buffer, 0xFF, sizeof(buffer));
+ ret = opj_sparse_array_int32_read(sa, 0, 0, 99, 101, buffer, 1, 99, OPJ_FALSE);
+ assert(ret);
+ for (i = 0; i < 99 * 101; i++) {
+ assert(buffer[i] == 0);
+ }
+
+ buffer[0] = 1;
+ ret = opj_sparse_array_int32_write(sa, 4, 5, 4 + 1, 5 + 1, buffer, 1, 1,
+ OPJ_FALSE);
+ assert(ret);
+ buffer[0] = 2;
+ ret = opj_sparse_array_int32_write(sa, 4, 5, 4 + 1, 5 + 1, buffer, 1, 1,
+ OPJ_FALSE);
+ assert(ret);
+
+ buffer[0] = 0;
+ buffer[1] = 0xFF;
+ ret = opj_sparse_array_int32_read(sa, 4, 5, 4 + 1, 5 + 1, buffer, 1, 1,
+ OPJ_FALSE);
+ assert(ret);
+ assert(buffer[0] == 2);
+ assert(buffer[1] == 0xFF);
+
+ w = 15 + 1;
+ h = 17 + 1;
+ memset(buffer, 0xFF, sizeof(buffer));
+ ret = opj_sparse_array_int32_read(sa, 2, 1, 2 + w, 1 + h, buffer, 1, w,
+ OPJ_FALSE);
+ assert(ret);
+ for (j = 0; j < h; j++) {
+ for (i = 0; i < w; i++) {
+ if (i == 4 - 2 && j == 5 - 1) {
+ assert(buffer[ j * w + i ] == 2);
+ } else {
+ assert(buffer[ j * w + i ] == 0);
+ }
+ }
+ }
+
+ opj_sparse_array_int32_free(sa);
+
+
+ sa = opj_sparse_array_int32_create(99, 101, 15, 17);
+ memset(buffer, 0xFF, sizeof(buffer));
+ ret = opj_sparse_array_int32_read(sa, 0, 0, 2, 1, buffer, 2, 4, OPJ_FALSE);
+ assert(ret);
+ assert(buffer[0] == 0);
+ assert(buffer[1] == -1);
+ assert(buffer[2] == 0);
+
+ buffer[0] = 1;
+ buffer[2] = 3;
+ ret = opj_sparse_array_int32_write(sa, 0, 0, 2, 1, buffer, 2, 4, OPJ_FALSE);
+ assert(ret);
+
+ memset(buffer, 0xFF, sizeof(buffer));
+ ret = opj_sparse_array_int32_read(sa, 0, 0, 2, 1, buffer, 2, 4, OPJ_FALSE);
+ assert(ret);
+ assert(buffer[0] == 1);
+ assert(buffer[1] == -1);
+ assert(buffer[2] == 3);
+
+ opj_sparse_array_int32_free(sa);
+
+ return 0;
+}