Sub-tile decoding: only allocate tile component buffer of the needed dimension

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.
This commit is contained in:
Even Rouault 2017-09-01 16:30:29 +02:00
parent aa7198146b
commit f9e9942330
13 changed files with 1334 additions and 506 deletions

View File

@ -253,7 +253,7 @@ if(BUILD_JPIP_SERVER)
endif() endif()
add_subdirectory(src/lib) add_subdirectory(src/lib)
option(BUILD_LUTS_GENERATOR "Build utility to generate t1_luts.h" OFF) 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 # Build Applications

View File

@ -54,6 +54,8 @@ set(OPENJPEG_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/opj_malloc.c ${CMAKE_CURRENT_SOURCE_DIR}/opj_malloc.c
${CMAKE_CURRENT_SOURCE_DIR}/opj_malloc.h ${CMAKE_CURRENT_SOURCE_DIR}/opj_malloc.h
${CMAKE_CURRENT_SOURCE_DIR}/opj_stdint.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) if(BUILD_JPIP)
add_definitions(-DUSE_JPIP) add_definitions(-DUSE_JPIP)
@ -192,12 +194,20 @@ if(OPJ_USE_THREAD AND Threads_FOUND AND CMAKE_USE_PTHREADS_INIT)
TARGET_LINK_LIBRARIES(${OPENJPEG_LIBRARY_NAME} ${CMAKE_THREAD_LIBS_INIT}) TARGET_LINK_LIBRARIES(${OPENJPEG_LIBRARY_NAME} ${CMAKE_THREAD_LIBS_INIT})
endif(OPJ_USE_THREAD AND Threads_FOUND AND CMAKE_USE_PTHREADS_INIT) endif(OPJ_USE_THREAD AND Threads_FOUND AND CMAKE_USE_PTHREADS_INIT)
if(BUILD_BENCH_DWT) if(BUILD_UNIT_TESTS)
add_executable(bench_dwt bench_dwt.c dwt.c opj_malloc.c thread.c) add_executable(bench_dwt bench_dwt.c)
if(UNIX) if(UNIX)
target_link_libraries(bench_dwt m) target_link_libraries(bench_dwt m ${OPENJPEG_LIBRARY_NAME})
endif() endif()
if(OPJ_USE_THREAD AND Threads_FOUND AND CMAKE_USE_PTHREADS_INIT) if(OPJ_USE_THREAD AND Threads_FOUND AND CMAKE_USE_PTHREADS_INIT)
target_link_libraries(bench_dwt ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries(bench_dwt ${CMAKE_THREAD_LIBS_INIT})
endif(OPJ_USE_THREAD AND Threads_FOUND AND CMAKE_USE_PTHREADS_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)

View File

@ -198,10 +198,11 @@ int main(int argc, char** argv)
memset(&tcd, 0, sizeof(tcd)); memset(&tcd, 0, sizeof(tcd));
tcd.thread_pool = tp; tcd.thread_pool = tp;
tcd.decoded_x0 = (OPJ_UINT32)tilec.x0; tcd.whole_tile_decoding = OPJ_TRUE;
tcd.decoded_y0 = (OPJ_UINT32)tilec.y0; tcd.win_x0 = (OPJ_UINT32)tilec.x0;
tcd.decoded_x1 = (OPJ_UINT32)tilec.x1; tcd.win_y0 = (OPJ_UINT32)tilec.y0;
tcd.decoded_y1 = (OPJ_UINT32)tilec.y1; tcd.win_x1 = (OPJ_UINT32)tilec.x1;
tcd.win_y1 = (OPJ_UINT32)tilec.y1;
tcd.tcd_image = &tcd_image; tcd.tcd_image = &tcd_image;
memset(&tcd_image, 0, sizeof(tcd_image)); memset(&tcd_image, 0, sizeof(tcd_image));
tcd_image.tiles = &tcd_tile; tcd_image.tiles = &tcd_tile;

View File

@ -151,7 +151,7 @@ Inverse wavelet transform in 2-D.
static OPJ_BOOL opj_dwt_decode_tile(opj_thread_pool_t* tp, static OPJ_BOOL opj_dwt_decode_tile(opj_thread_pool_t* tp,
opj_tcd_tilecomp_t* tilec, OPJ_UINT32 i); opj_tcd_tilecomp_t* tilec, OPJ_UINT32 i);
static OPJ_BOOL opj_dwt_decode_partial_tile(opj_tcd_t *p_tcd, static OPJ_BOOL opj_dwt_decode_partial_tile(
opj_tcd_tilecomp_t* tilec, opj_tcd_tilecomp_t* tilec,
OPJ_UINT32 numres); OPJ_UINT32 numres);
@ -1194,50 +1194,16 @@ OPJ_BOOL opj_dwt_encode(opj_tcd_tilecomp_t * tilec)
return opj_dwt_encode_procedure(tilec, opj_dwt_encode_1); 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> */ /* <summary> */
/* Inverse 5-3 wavelet transform in 2-D. */ /* Inverse 5-3 wavelet transform in 2-D. */
/* </summary> */ /* </summary> */
OPJ_BOOL opj_dwt_decode(opj_tcd_t *p_tcd, opj_tcd_tilecomp_t* tilec, OPJ_BOOL opj_dwt_decode(opj_tcd_t *p_tcd, opj_tcd_tilecomp_t* tilec,
OPJ_UINT32 numres) 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); return opj_dwt_decode_tile(p_tcd->thread_pool, tilec, numres);
} else { } else {
return opj_dwt_decode_partial_tile(p_tcd, tilec, numres); return opj_dwt_decode_partial_tile(tilec, numres);
} }
} }
@ -1403,7 +1369,9 @@ static OPJ_BOOL opj_dwt_decode_tile(opj_thread_pool_t* tp,
OPJ_UINT32 rh = (OPJ_UINT32)(tr->y1 - OPJ_UINT32 rh = (OPJ_UINT32)(tr->y1 -
tr->y0); /* height of the resolution level computed */ 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; size_t h_mem_size;
int num_threads; int num_threads;
@ -1552,51 +1520,53 @@ static OPJ_BOOL opj_dwt_decode_tile(opj_thread_pool_t* tp,
static void opj_dwt_interleave_partial_h(OPJ_INT32 *dest, static void opj_dwt_interleave_partial_h(OPJ_INT32 *dest,
OPJ_INT32 cas, OPJ_INT32 cas,
const OPJ_INT32* src, opj_sparse_array_int32_t* sa,
OPJ_INT32 sn, OPJ_UINT32 sa_line,
OPJ_INT32 win_l_x0, OPJ_UINT32 sn,
OPJ_INT32 win_l_x1, OPJ_UINT32 win_l_x0,
OPJ_INT32 win_h_x0, OPJ_UINT32 win_l_x1,
OPJ_INT32 win_h_x1) OPJ_UINT32 win_h_x0,
OPJ_UINT32 win_h_x1)
{ {
const OPJ_INT32 *ai = src; OPJ_BOOL ret;
OPJ_INT32 *bi = dest + cas; ret = opj_sparse_array_int32_read(sa,
OPJ_INT32 i; win_l_x0, sa_line,
win_l_x1, sa_line + 1,
for (i = win_l_x0; i < win_l_x1; i++) { dest + cas + 2 * win_l_x0,
bi[2 * i] = ai[i]; 2, 0, OPJ_TRUE);
} assert(ret);
ret = opj_sparse_array_int32_read(sa,
ai = src + sn; sn + win_h_x0, sa_line,
bi = dest + 1 - cas; sn + win_h_x1, sa_line + 1,
for (i = win_h_x0; i < win_h_x1; i++) { dest + 1 - cas + 2 * win_h_x0,
bi[2 * i] = ai[i]; 2, 0, OPJ_TRUE);
} assert(ret);
} }
static void opj_dwt_interleave_partial_v(OPJ_INT32 *dest, static void opj_dwt_interleave_partial_v(OPJ_INT32 *dest,
OPJ_INT32 cas, OPJ_INT32 cas,
const OPJ_INT32* src, opj_sparse_array_int32_t* sa,
OPJ_INT32 sn, OPJ_UINT32 sa_col,
OPJ_INT32 stride, OPJ_UINT32 sn,
OPJ_INT32 win_l_y0, OPJ_UINT32 win_l_y0,
OPJ_INT32 win_l_y1, OPJ_UINT32 win_l_y1,
OPJ_INT32 win_h_y0, OPJ_UINT32 win_h_y0,
OPJ_INT32 win_h_y1) OPJ_UINT32 win_h_y1)
{ {
const OPJ_INT32 *ai = src; OPJ_BOOL ret;
OPJ_INT32 *bi = dest + cas; ret = opj_sparse_array_int32_read(sa,
OPJ_INT32 i; sa_col, win_l_y0,
sa_col + 1, win_l_y1,
for (i = win_l_y0; i < win_l_y1; i++) { dest + cas + 2 * win_l_y0,
bi[2 * i] = ai[i * stride]; 0, 2, OPJ_TRUE);
} assert(ret);
ret = opj_sparse_array_int32_read(sa,
ai = src + sn * stride; sa_col, sn + win_h_y0,
bi = dest + 1 - cas; sa_col + 1, sn + win_h_y1,
for (i = win_h_y0; i < win_h_y1; i++) { dest + 1 - cas + 2 * win_h_y0,
bi[2 * i] = ai[i * stride]; 0, 2, OPJ_TRUE);
} assert(ret);
} }
static void opj_dwt_decode_partial_1(OPJ_INT32 *a, OPJ_INT32 dn, OPJ_INT32 sn, static void opj_dwt_decode_partial_1(OPJ_INT32 *a, OPJ_INT32 dn, OPJ_INT32 sn,
@ -1683,10 +1653,68 @@ static void opj_dwt_segment_grow(OPJ_UINT32 filter_width,
*end = opj_uint_min(*end, max_size); *end = opj_uint_min(*end, max_size);
} }
static OPJ_BOOL opj_dwt_decode_partial_tile(opj_tcd_t *tcd,
static opj_sparse_array_int32_t* opj_dwt_init_sparse_array(
opj_tcd_tilecomp_t* tilec, opj_tcd_tilecomp_t* tilec,
OPJ_UINT32 numres) 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 h;
opj_dwt_t v; opj_dwt_t v;
OPJ_UINT32 resno; OPJ_UINT32 resno;
@ -1695,38 +1723,42 @@ static OPJ_BOOL opj_dwt_decode_partial_tile(opj_tcd_t *tcd,
const OPJ_UINT32 filter_width = 2U; const OPJ_UINT32 filter_width = 2U;
opj_tcd_resolution_t* tr = tilec->resolutions; opj_tcd_resolution_t* tr = tilec->resolutions;
opj_tcd_resolution_t* tr_max = &(tilec->resolutions[numres - 1]);
OPJ_UINT32 rw = (OPJ_UINT32)(tr->x1 - OPJ_UINT32 rw = (OPJ_UINT32)(tr->x1 -
tr->x0); /* width of the resolution level computed */ tr->x0); /* width of the resolution level computed */
OPJ_UINT32 rh = (OPJ_UINT32)(tr->y1 - OPJ_UINT32 rh = (OPJ_UINT32)(tr->y1 -
tr->y0); /* height of the resolution level computed */ tr->y0); /* height of the resolution level computed */
OPJ_UINT32 w = (OPJ_UINT32)(tilec->x1 - tilec->x0);
size_t h_mem_size; 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 */ /* Compute the intersection of the area of interest, expressed in tile coordinates */
/* with the tile coordinates */ /* with the tile coordinates */
OPJ_UINT32 win_tcx0 = opj_uint_max( OPJ_UINT32 win_tcx0 = tilec->win_x0;
(OPJ_UINT32)tilec->x0, OPJ_UINT32 win_tcy0 = tilec->win_y0;
opj_uint_ceildiv(tcd->decoded_x0, image_comp->dx)); OPJ_UINT32 win_tcx1 = tilec->win_x1;
OPJ_UINT32 win_tcy0 = opj_uint_max( OPJ_UINT32 win_tcy1 = tilec->win_y1;
(OPJ_UINT32)tilec->y0,
opj_uint_ceildiv(tcd->decoded_y0, image_comp->dy)); sa = opj_dwt_init_sparse_array(tilec, numres);
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));
if (numres == 1U) { 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; return OPJ_TRUE;
} }
h_mem_size = opj_dwt_max_resolution(tr, numres); h_mem_size = opj_dwt_max_resolution(tr, numres);
/* overflow check */ /* overflow check */
if (h_mem_size > (SIZE_MAX / sizeof(OPJ_INT32))) { if (h_mem_size > (SIZE_MAX / sizeof(OPJ_INT32))) {
/* FIXME event manager error callback */ /* FIXME event manager error callback */
opj_sparse_array_int32_free(sa);
return OPJ_FALSE; return OPJ_FALSE;
} }
@ -1734,13 +1766,13 @@ static OPJ_BOOL opj_dwt_decode_partial_tile(opj_tcd_t *tcd,
h.mem = (OPJ_INT32*)opj_aligned_32_malloc(h_mem_size); h.mem = (OPJ_INT32*)opj_aligned_32_malloc(h_mem_size);
if (! h.mem) { if (! h.mem) {
/* FIXME event manager error callback */ /* FIXME event manager error callback */
opj_sparse_array_int32_free(sa);
return OPJ_FALSE; return OPJ_FALSE;
} }
v.mem = h.mem; v.mem = h.mem;
for (resno = 1; --numres > 0; resno ++) { for (resno = 1; resno < numres; resno ++) {
OPJ_INT32 * OPJ_RESTRICT tiledp = tilec->data;
OPJ_UINT32 i, j; OPJ_UINT32 i, j;
/* Window of interest subband-based coordinates */ /* Window of interest subband-based coordinates */
OPJ_UINT32 win_ll_x0, win_ll_y0, win_ll_x1, win_ll_y1; OPJ_UINT32 win_ll_x0, win_ll_y0, win_ll_x1, win_ll_y1;
@ -1826,47 +1858,74 @@ static OPJ_BOOL opj_dwt_decode_partial_tile(opj_tcd_t *tcd,
for (j = 0; j < rh; ++j) { for (j = 0; j < rh; ++j) {
if ((j >= win_ll_y0 && j < win_ll_y1) || 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)) { (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, opj_dwt_interleave_partial_h(h.mem,
h.cas, h.cas,
&tiledp[j * w], sa,
h.sn, j,
(OPJ_INT32)win_ll_x0, (OPJ_UINT32)h.sn,
(OPJ_INT32)win_ll_x1, win_ll_x0,
(OPJ_INT32)win_hl_x0, win_ll_x1,
(OPJ_INT32)win_hl_x1); win_hl_x0,
win_hl_x1);
opj_dwt_decode_partial_1(h.mem, h.dn, h.sn, h.cas, opj_dwt_decode_partial_1(h.mem, h.dn, h.sn, h.cas,
(OPJ_INT32)win_ll_x0, (OPJ_INT32)win_ll_x0,
(OPJ_INT32)win_ll_x1, (OPJ_INT32)win_ll_x1,
(OPJ_INT32)win_hl_x0, (OPJ_INT32)win_hl_x0,
(OPJ_INT32)win_hl_x1); (OPJ_INT32)win_hl_x1);
memcpy(&tiledp[j * w] + win_tr_x0, h.mem + win_tr_x0, if (!opj_sparse_array_int32_write(sa,
(win_tr_x1 - win_tr_x0) * sizeof(OPJ_INT32)); 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) { 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, opj_dwt_interleave_partial_v(v.mem,
v.cas, v.cas,
tiledp + i, sa,
v.sn, i,
(OPJ_INT32)w, (OPJ_UINT32)v.sn,
(OPJ_INT32)win_ll_y0, win_ll_y0,
(OPJ_INT32)win_ll_y1, win_ll_y1,
(OPJ_INT32)win_lh_y0, win_lh_y0,
(OPJ_INT32)win_lh_y1); win_lh_y1);
opj_dwt_decode_partial_1(v.mem, v.dn, v.sn, v.cas, opj_dwt_decode_partial_1(v.mem, v.dn, v.sn, v.cas,
(OPJ_INT32)win_ll_y0, (OPJ_INT32)win_ll_y0,
(OPJ_INT32)win_ll_y1, (OPJ_INT32)win_ll_y1,
(OPJ_INT32)win_lh_y0, (OPJ_INT32)win_lh_y0,
(OPJ_INT32)win_lh_y1); (OPJ_INT32)win_lh_y1);
for (j = win_tr_y0; j < win_tr_y1; j++) { if (!opj_sparse_array_int32_write(sa,
tiledp[j * w + i] = v.mem[j]; 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_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; return OPJ_TRUE;
} }
@ -1924,6 +1983,31 @@ static void opj_v4dwt_interleave_h(opj_v4dwt_t* OPJ_RESTRICT dwt,
} }
} }
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, static void opj_v4dwt_interleave_v(opj_v4dwt_t* OPJ_RESTRICT dwt,
OPJ_FLOAT32* OPJ_RESTRICT a, OPJ_FLOAT32* OPJ_RESTRICT a,
OPJ_UINT32 width, OPJ_UINT32 width,
@ -1944,6 +2028,29 @@ static void opj_v4dwt_interleave_v(opj_v4dwt_t* OPJ_RESTRICT dwt,
} }
} }
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__ #ifdef __SSE__
static void opj_v4dwt_decode_step1_sse(opj_v4_t* w, static void opj_v4dwt_decode_step1_sse(opj_v4_t* w,
@ -2146,7 +2253,9 @@ OPJ_BOOL opj_dwt_decode_tile_97(opj_tcd_tilecomp_t* OPJ_RESTRICT tilec,
OPJ_UINT32 rh = (OPJ_UINT32)(res->y1 - OPJ_UINT32 rh = (OPJ_UINT32)(res->y1 -
res->y0); /* height of the resolution level computed */ 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; size_t l_data_size;
@ -2262,10 +2371,10 @@ OPJ_BOOL opj_dwt_decode_tile_97(opj_tcd_tilecomp_t* OPJ_RESTRICT tilec,
} }
static static
OPJ_BOOL opj_dwt_decode_partial_97(opj_tcd_t *tcd, OPJ_BOOL opj_dwt_decode_partial_97(opj_tcd_tilecomp_t* OPJ_RESTRICT tilec,
opj_tcd_tilecomp_t* OPJ_RESTRICT tilec,
OPJ_UINT32 numres) OPJ_UINT32 numres)
{ {
opj_sparse_array_int32_t* sa;
opj_v4dwt_t h; opj_v4dwt_t h;
opj_v4dwt_t v; opj_v4dwt_t v;
OPJ_UINT32 resno; OPJ_UINT32 resno;
@ -2275,31 +2384,37 @@ OPJ_BOOL opj_dwt_decode_partial_97(opj_tcd_t *tcd,
const OPJ_UINT32 filter_width = 4U; const OPJ_UINT32 filter_width = 4U;
opj_tcd_resolution_t* tr = tilec->resolutions; opj_tcd_resolution_t* tr = tilec->resolutions;
opj_tcd_resolution_t* tr_max = &(tilec->resolutions[numres - 1]);
OPJ_UINT32 rw = (OPJ_UINT32)(tr->x1 - OPJ_UINT32 rw = (OPJ_UINT32)(tr->x1 -
tr->x0); /* width of the resolution level computed */ tr->x0); /* width of the resolution level computed */
OPJ_UINT32 rh = (OPJ_UINT32)(tr->y1 - OPJ_UINT32 rh = (OPJ_UINT32)(tr->y1 -
tr->y0); /* height of the resolution level computed */ tr->y0); /* height of the resolution level computed */
OPJ_UINT32 w = (OPJ_UINT32)(tilec->x1 - tilec->x0);
size_t l_data_size; 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 */ /* Compute the intersection of the area of interest, expressed in tile coordinates */
/* with the tile coordinates */ /* with the tile coordinates */
OPJ_UINT32 win_tcx0 = opj_uint_max( OPJ_UINT32 win_tcx0 = tilec->win_x0;
(OPJ_UINT32)tilec->x0, OPJ_UINT32 win_tcy0 = tilec->win_y0;
opj_uint_ceildiv(tcd->decoded_x0, image_comp->dx)); OPJ_UINT32 win_tcx1 = tilec->win_x1;
OPJ_UINT32 win_tcy0 = opj_uint_max( OPJ_UINT32 win_tcy1 = tilec->win_y1;
(OPJ_UINT32)tilec->y0,
opj_uint_ceildiv(tcd->decoded_y0, image_comp->dy)); sa = opj_dwt_init_sparse_array(tilec, numres);
OPJ_UINT32 win_tcx1 = opj_uint_min(
(OPJ_UINT32)tilec->x1, if (numres == 1U) {
opj_uint_ceildiv(tcd->decoded_x1, image_comp->dx)); OPJ_BOOL ret = opj_sparse_array_int32_read(sa,
OPJ_UINT32 win_tcy1 = opj_uint_min( tr_max->win_x0 - (OPJ_UINT32)tr_max->x0,
(OPJ_UINT32)tilec->y1, tr_max->win_y0 - (OPJ_UINT32)tr_max->y0,
opj_uint_ceildiv(tcd->decoded_y1, image_comp->dy)); 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); l_data_size = opj_dwt_max_resolution(tr, numres);
/* overflow check */ /* overflow check */
@ -2320,8 +2435,7 @@ OPJ_BOOL opj_dwt_decode_partial_97(opj_tcd_t *tcd,
} }
v.wavelet = h.wavelet; v.wavelet = h.wavelet;
for (resno = 1; --numres; resno++) { for (resno = 1; resno < numres; resno ++) {
OPJ_FLOAT32 * OPJ_RESTRICT aj = (OPJ_FLOAT32*) tilec->data;
OPJ_UINT32 j; OPJ_UINT32 j;
/* Window of interest subband-based coordinates */ /* Window of interest subband-based coordinates */
OPJ_UINT32 win_ll_x0, win_ll_y0, win_ll_x1, win_ll_y1; OPJ_UINT32 win_ll_x0, win_ll_y0, win_ll_x1, win_ll_y1;
@ -2408,19 +2522,24 @@ OPJ_BOOL opj_dwt_decode_partial_97(opj_tcd_t *tcd,
h.win_l_x1 = win_ll_x1; h.win_l_x1 = win_ll_x1;
h.win_h_x0 = win_hl_x0; h.win_h_x0 = win_hl_x0;
h.win_h_x1 = win_hl_x1; 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) || if ((j + 3 >= win_ll_y0 && j < win_ll_y1) ||
(j + 3 >= win_lh_y0 + (OPJ_UINT32)v.sn && (j + 3 >= win_lh_y0 + (OPJ_UINT32)v.sn &&
j < win_lh_y1 + (OPJ_UINT32)v.sn)) { j < win_lh_y1 + (OPJ_UINT32)v.sn)) {
OPJ_UINT32 k; 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); opj_v4dwt_decode(&h);
for (k = 0; k < 4; k++) {
for (k = win_tr_x0; k < win_tr_x1; k++) { if (!opj_sparse_array_int32_write(sa,
aj[k ] = h.wavelet[k].f[0]; win_tr_x0, j + k,
aj[k + w ] = h.wavelet[k].f[1]; win_tr_x1, j + k + 1,
aj[k + w * 2] = h.wavelet[k].f[2]; (OPJ_INT32*)&h.wavelet[win_tr_x0].f[k],
aj[k + w * 3] = h.wavelet[k].f[3]; 4, 0, OPJ_TRUE)) {
/* FIXME event manager error callback */
opj_sparse_array_int32_free(sa);
opj_aligned_free(h.wavelet);
return OPJ_FALSE;
}
} }
} }
} }
@ -2430,18 +2549,18 @@ OPJ_BOOL opj_dwt_decode_partial_97(opj_tcd_t *tcd,
(j + 3 >= win_lh_y0 + (OPJ_UINT32)v.sn && (j + 3 >= win_lh_y0 + (OPJ_UINT32)v.sn &&
j < win_lh_y1 + (OPJ_UINT32)v.sn))) { j < win_lh_y1 + (OPJ_UINT32)v.sn))) {
OPJ_UINT32 k; 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); opj_v4dwt_decode(&h);
for (k = win_tr_x0; k < win_tr_x1; k++) { for (k = 0; k < rh - j; k++) {
switch (rh - j) { if (!opj_sparse_array_int32_write(sa,
case 3: win_tr_x0, j + k,
aj[k + w * 2] = h.wavelet[k].f[2]; win_tr_x1, j + k + 1,
/* FALLTHRU */ (OPJ_INT32*)&h.wavelet[win_tr_x0].f[k],
case 2: 4, 0, OPJ_TRUE)) {
aj[k + w ] = h.wavelet[k].f[1]; /* FIXME event manager error callback */
/* FALLTHRU */ opj_sparse_array_int32_free(sa);
case 1: opj_aligned_free(h.wavelet);
aj[k ] = h.wavelet[k].f[0]; return OPJ_FALSE;
} }
} }
} }
@ -2450,20 +2569,40 @@ OPJ_BOOL opj_dwt_decode_partial_97(opj_tcd_t *tcd,
v.win_l_x1 = win_ll_y1; v.win_l_x1 = win_ll_y1;
v.win_h_x0 = win_lh_y0; v.win_h_x0 = win_lh_y0;
v.win_h_x1 = win_lh_y1; v.win_h_x1 = win_lh_y1;
aj = (OPJ_FLOAT32*) tilec->data; for (j = win_tr_x0; j < win_tr_x1; j += 4) {
aj += win_tr_x0;
for (j = win_tr_x0; j < win_tr_x1; j += 4, aj += 4) {
OPJ_UINT32 nb_elts = opj_uint_min(4U, win_tr_x1 - j); OPJ_UINT32 nb_elts = opj_uint_min(4U, win_tr_x1 - j);
OPJ_UINT32 k; 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); opj_v4dwt_decode(&v);
for (k = win_tr_y0; k < win_tr_y1; ++k) { for (k = 0; k < nb_elts; k++) {
memcpy(&aj[k * w], &v.wavelet[k], nb_elts * sizeof(OPJ_FLOAT32)); 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); opj_aligned_free(h.wavelet);
return OPJ_TRUE; return OPJ_TRUE;
@ -2474,9 +2613,9 @@ OPJ_BOOL opj_dwt_decode_real(opj_tcd_t *p_tcd,
opj_tcd_tilecomp_t* OPJ_RESTRICT tilec, opj_tcd_tilecomp_t* OPJ_RESTRICT tilec,
OPJ_UINT32 numres) 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); return opj_dwt_decode_tile_97(tilec, numres);
} else { } else {
return opj_dwt_decode_partial_97(p_tcd, tilec, numres); return opj_dwt_decode_partial_97(tilec, numres);
} }
} }

View File

@ -63,7 +63,7 @@ OPJ_BOOL opj_dwt_encode(opj_tcd_tilecomp_t * tilec);
/** /**
Inverse 5-3 wavelet transform in 2-D. Inverse 5-3 wavelet transform in 2-D.
Apply a reversible inverse DWT transform to a component of an image. 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 tilec Tile component information (current tile)
@param numres Number of resolution levels to decode @param numres Number of resolution levels to decode
*/ */
@ -93,7 +93,7 @@ OPJ_BOOL opj_dwt_encode_real(opj_tcd_tilecomp_t * tilec);
/** /**
Inverse 9-7 wavelet transform in 2-D. Inverse 9-7 wavelet transform in 2-D.
Apply an irreversible inverse DWT transform to a component of an image. 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 tilec Tile component information (current tile)
@param numres Number of resolution levels to decode @param numres Number of resolution levels to decode
*/ */

View File

@ -49,8 +49,6 @@
/** @name Local static functions */ /** @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. * Sets up the procedures to do on reading header. Developpers wanting to extend the library can add their own reading procedures.
*/ */
@ -371,7 +369,7 @@ static OPJ_BOOL opj_j2k_pre_write_tile(opj_j2k_t * p_j2k,
opj_stream_private_t *p_stream, opj_stream_private_t *p_stream,
opj_event_mgr_t * p_manager); 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); opj_image_t* p_output_image);
static void opj_get_tile_dimensions(opj_image_t * l_image, static void opj_get_tile_dimensions(opj_image_t * l_image,
@ -8789,7 +8787,7 @@ OPJ_BOOL opj_j2k_read_tile_header(opj_j2k_t * p_j2k,
*p_tile_index = p_j2k->m_current_tile_number; *p_tile_index = p_j2k->m_current_tile_number;
*p_go_on = OPJ_TRUE; *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) { if (*p_data_size == UINT_MAX) {
return OPJ_FALSE; return OPJ_FALSE;
} }
@ -8902,26 +8900,24 @@ OPJ_BOOL opj_j2k_decode_tile(opj_j2k_t * p_j2k,
return OPJ_TRUE; 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_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_src, l_height_src;
OPJ_UINT32 l_width_dest, l_height_dest; 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_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_start_x_dest, l_start_y_dest;
OPJ_UINT32 l_x0_dest, l_y0_dest, l_x1_dest, l_y1_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_src = 00;
opj_image_comp_t * l_img_comp_dest = 00; opj_image_comp_t * l_img_comp_dest = 00;
opj_tcd_tilecomp_t * l_tilec = 00; opj_tcd_tilecomp_t * l_tilec = 00;
opj_image_t * l_image_src = 00; opj_image_t * l_image_src = 00;
OPJ_UINT32 l_size_comp, l_remaining;
OPJ_INT32 * l_dest_ptr; OPJ_INT32 * l_dest_ptr;
opj_tcd_resolution_t* l_res = 00;
l_tilec = p_tcd->tcd_image->tiles->comps; l_tilec = p_tcd->tcd_image->tiles->comps;
l_image_src = p_tcd->image; l_image_src = p_tcd->image;
@ -8930,6 +8926,9 @@ static OPJ_BOOL opj_j2k_update_image_data(opj_tcd_t * p_tcd, OPJ_BYTE * p_data,
l_img_comp_dest = p_output_image->comps; l_img_comp_dest = p_output_image->comps;
for (i = 0; i < l_image_src->numcomps; i++) { 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 */ /* Allocate output component buffer if necessary */
if (!l_img_comp_dest->data) { if (!l_img_comp_dest->data) {
@ -8953,29 +8952,38 @@ static OPJ_BOOL opj_j2k_update_image_data(opj_tcd_t * p_tcd, OPJ_BYTE * p_data,
/* Copy info from decoded comp image to output image */ /* Copy info from decoded comp image to output image */
l_img_comp_dest->resno_decoded = l_img_comp_src->resno_decoded; l_img_comp_dest->resno_decoded = l_img_comp_src->resno_decoded;
/*-----*/ if (p_tcd->whole_tile_decoding) {
/* Compute the precision of the output buffer */ opj_tcd_resolution_t* l_res = l_tilec->resolutions +
l_size_comp = l_img_comp_src->prec >> 3; /*(/ 8)*/ l_img_comp_src->resno_decoded;
l_remaining = l_img_comp_src->prec & 7; /* (%8) */ res_x0 = l_res->x0;
l_res = l_tilec->resolutions + l_img_comp_src->resno_decoded; res_y0 = l_res->y0;
res_x1 = l_res->x1;
if (l_remaining) { res_y1 = l_res->y1;
++l_size_comp; 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_width_src = (OPJ_UINT32)(res_x1 - res_x0);
l_size_comp = 4; l_height_src = (OPJ_UINT32)(res_y1 - res_y0);
}
/*-----*/
/* Current tile component size*/ /* Current tile component size*/
/*if (i == 0) { /*if (i == 0) {
fprintf(stdout, "SRC: l_res_x0=%d, l_res_x1=%d, l_res_y0=%d, l_res_y1=%d\n", 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*/ /* Border of the current output component*/
l_x0_dest = opj_uint_ceildivpow2(l_img_comp_dest->x0, l_img_comp_dest->factor); l_x0_dest = opj_uint_ceildivpow2(l_img_comp_dest->x0, l_img_comp_dest->factor);
@ -8996,53 +9004,53 @@ static OPJ_BOOL opj_j2k_update_image_data(opj_tcd_t * p_tcd, OPJ_BYTE * p_data,
* l_start_y_dest, l_width_dest, l_height_dest) which will be modified * l_start_y_dest, l_width_dest, l_height_dest) which will be modified
* by this input area. * by this input area.
* */ * */
assert(l_res->x0 >= 0); assert(res_x0 >= 0);
assert(l_res->x1 >= 0); assert(res_x1 >= 0);
if (l_x0_dest < (OPJ_UINT32)l_res->x0) { if (l_x0_dest < (OPJ_UINT32)res_x0) {
l_start_x_dest = (OPJ_UINT32)l_res->x0 - l_x0_dest; l_start_x_dest = (OPJ_UINT32)res_x0 - l_x0_dest;
l_offset_x0_src = 0; 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_width_dest = l_width_src;
l_offset_x1_src = 0; l_offset_x1_src = 0;
} else { } 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); l_offset_x1_src = (OPJ_INT32)(l_width_src - l_width_dest);
} }
} else { } else {
l_start_x_dest = 0U; 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_width_dest = l_width_src - (OPJ_UINT32)l_offset_x0_src;
l_offset_x1_src = 0; l_offset_x1_src = 0;
} else { } else {
l_width_dest = l_img_comp_dest->w ; 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) { if (l_y0_dest < (OPJ_UINT32)res_y0) {
l_start_y_dest = (OPJ_UINT32)l_res->y0 - l_y0_dest; l_start_y_dest = (OPJ_UINT32)res_y0 - l_y0_dest;
l_offset_y0_src = 0; 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_height_dest = l_height_src;
l_offset_y1_src = 0; l_offset_y1_src = 0;
} else { } 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); l_offset_y1_src = (OPJ_INT32)(l_height_src - l_height_dest);
} }
} else { } else {
l_start_y_dest = 0U; 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_height_dest = l_height_src - (OPJ_UINT32)l_offset_y0_src;
l_offset_y1_src = 0; l_offset_y1_src = 0;
} else { } else {
l_height_dest = l_img_comp_dest->h ; 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;
} }
} }
@ -9058,114 +9066,24 @@ static OPJ_BOOL opj_j2k_update_image_data(opj_tcd_t * p_tcd, OPJ_BYTE * p_data,
/* Compute the input buffer offset */ /* Compute the input buffer offset */
l_start_offset_src = (OPJ_SIZE_T)l_offset_x0_src + (OPJ_SIZE_T)l_offset_y0_src l_start_offset_src = (OPJ_SIZE_T)l_offset_x0_src + (OPJ_SIZE_T)l_offset_y0_src
* (OPJ_SIZE_T)l_width_src; * (OPJ_SIZE_T)src_data_stride;
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;
/* Compute the output buffer offset */ /* Compute the output buffer offset */
l_start_offset_dest = (OPJ_SIZE_T)l_start_x_dest + (OPJ_SIZE_T)l_start_y_dest 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; * (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*/ /* Move the output buffer to the first place where we will write*/
l_dest_ptr = l_img_comp_dest->data + l_start_offset_dest; l_dest_ptr = l_img_comp_dest->data + l_start_offset_dest;
/*if (i == 0) { {
fprintf(stdout, "COMPO[%d]:\n",i); const OPJ_INT32 * l_src_ptr = p_src_data;
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;
l_src_ptr += l_start_offset_src; l_src_ptr += l_start_offset_src;
for (j = 0; j < l_height_dest; ++j) { for (j = 0; j < l_height_dest; ++j) {
memcpy(l_dest_ptr, l_src_ptr, l_width_dest * sizeof(OPJ_INT32)); memcpy(l_dest_ptr, l_src_ptr, l_width_dest * sizeof(OPJ_INT32));
l_dest_ptr += l_width_dest + l_line_offset_dest; l_dest_ptr += l_img_comp_dest->w;
l_src_ptr += l_width_dest + l_line_offset_src ; 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; ++l_img_comp_dest;
@ -10548,10 +10466,9 @@ static OPJ_BOOL opj_j2k_decode_tiles(opj_j2k_t *p_j2k,
{ {
OPJ_BOOL l_go_on = OPJ_TRUE; OPJ_BOOL l_go_on = OPJ_TRUE;
OPJ_UINT32 l_current_tile_no; 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_INT32 l_tile_x0, l_tile_y0, l_tile_x1, l_tile_y1;
OPJ_UINT32 l_nb_comps; OPJ_UINT32 l_nb_comps;
OPJ_BYTE * l_current_data;
OPJ_UINT32 nr_tiles = 0; OPJ_UINT32 nr_tiles = 0;
/* Particular case for whole single tile decoding */ /* Particular case for whole single tile decoding */
@ -10595,13 +10512,6 @@ static OPJ_BOOL opj_j2k_decode_tiles(opj_j2k_t *p_j2k,
return OPJ_TRUE; 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 (;;) { for (;;) {
if (! opj_j2k_read_tile_header(p_j2k, if (! opj_j2k_read_tile_header(p_j2k,
&l_current_tile_no, &l_current_tile_no,
@ -10612,7 +10522,6 @@ static OPJ_BOOL opj_j2k_decode_tiles(opj_j2k_t *p_j2k,
&l_go_on, &l_go_on,
p_stream, p_stream,
p_manager)) { p_manager)) {
opj_free(l_current_data);
return OPJ_FALSE; return OPJ_FALSE;
} }
@ -10620,34 +10529,22 @@ static OPJ_BOOL opj_j2k_decode_tiles(opj_j2k_t *p_j2k,
break; break;
} }
if (l_data_size > l_max_data_size) { if (! opj_j2k_decode_tile(p_j2k, l_current_tile_no, NULL, 0,
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,
p_stream, p_manager)) { p_stream, p_manager)) {
opj_free(l_current_data);
opj_event_msg(p_manager, EVT_ERROR, "Failed to decode tile %d/%d\n", 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); l_current_tile_no + 1, p_j2k->m_cp.th * p_j2k->m_cp.tw);
return OPJ_FALSE; return OPJ_FALSE;
} }
opj_event_msg(p_manager, EVT_INFO, "Tile %d/%d has been decoded.\n", 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); 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)) { p_j2k->m_output_image)) {
opj_free(l_current_data);
return OPJ_FALSE; return OPJ_FALSE;
} }
opj_j2k_tcp_data_destroy(&p_j2k->m_cp.tcps[l_current_tile_no]);
opj_event_msg(p_manager, EVT_INFO, opj_event_msg(p_manager, EVT_INFO,
"Image data has been updated with tile %d.\n\n", l_current_tile_no + 1); "Image data has been updated with tile %d.\n\n", l_current_tile_no + 1);
@ -10660,8 +10557,6 @@ static OPJ_BOOL opj_j2k_decode_tiles(opj_j2k_t *p_j2k,
} }
} }
opj_free(l_current_data);
return OPJ_TRUE; return OPJ_TRUE;
} }
@ -10694,24 +10589,15 @@ static OPJ_BOOL opj_j2k_decode_one_tile(opj_j2k_t *p_j2k,
OPJ_BOOL l_go_on = OPJ_TRUE; OPJ_BOOL l_go_on = OPJ_TRUE;
OPJ_UINT32 l_current_tile_no; OPJ_UINT32 l_current_tile_no;
OPJ_UINT32 l_tile_no_to_dec; 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_INT32 l_tile_x0, l_tile_y0, l_tile_x1, l_tile_y1;
OPJ_UINT32 l_nb_comps; OPJ_UINT32 l_nb_comps;
OPJ_BYTE * l_current_data;
OPJ_UINT32 l_nb_tiles; OPJ_UINT32 l_nb_tiles;
OPJ_UINT32 i; 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*/ /*Allocate and initialize some elements of codestrem index if not already done*/
if (!p_j2k->cstr_index->tile_index) { if (!p_j2k->cstr_index->tile_index) {
if (!opj_j2k_allocate_tile_element_cstr_index(p_j2k)) { if (!opj_j2k_allocate_tile_element_cstr_index(p_j2k)) {
opj_free(l_current_data);
return OPJ_FALSE; return OPJ_FALSE;
} }
} }
@ -10726,7 +10612,6 @@ static OPJ_BOOL opj_j2k_decode_one_tile(opj_j2k_t *p_j2k,
if (!(opj_stream_read_seek(p_stream, if (!(opj_stream_read_seek(p_stream,
p_j2k->m_specific_param.m_decoder.m_last_sot_read_pos + 2, p_manager))) { 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_event_msg(p_manager, EVT_ERROR, "Problem with seek function\n");
opj_free(l_current_data);
return OPJ_FALSE; return OPJ_FALSE;
} }
} else { } else {
@ -10734,7 +10619,6 @@ static OPJ_BOOL opj_j2k_decode_one_tile(opj_j2k_t *p_j2k,
p_j2k->cstr_index->tile_index[l_tile_no_to_dec].tp_index[0].start_pos + 2, p_j2k->cstr_index->tile_index[l_tile_no_to_dec].tp_index[0].start_pos + 2,
p_manager))) { p_manager))) {
opj_event_msg(p_manager, EVT_ERROR, "Problem with seek function\n"); opj_event_msg(p_manager, EVT_ERROR, "Problem with seek function\n");
opj_free(l_current_data);
return OPJ_FALSE; return OPJ_FALSE;
} }
} }
@ -10763,7 +10647,6 @@ static OPJ_BOOL opj_j2k_decode_one_tile(opj_j2k_t *p_j2k,
&l_go_on, &l_go_on,
p_stream, p_stream,
p_manager)) { p_manager)) {
opj_free(l_current_data);
return OPJ_FALSE; return OPJ_FALSE;
} }
@ -10771,33 +10654,19 @@ static OPJ_BOOL opj_j2k_decode_one_tile(opj_j2k_t *p_j2k,
break; break;
} }
if (l_data_size > l_max_data_size) { if (! opj_j2k_decode_tile(p_j2k, l_current_tile_no, NULL, 0,
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,
p_stream, p_manager)) { p_stream, p_manager)) {
opj_free(l_current_data);
return OPJ_FALSE; return OPJ_FALSE;
} }
opj_event_msg(p_manager, EVT_INFO, "Tile %d/%d has been decoded.\n", 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); 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)) { p_j2k->m_output_image)) {
opj_free(l_current_data);
return OPJ_FALSE; return OPJ_FALSE;
} }
opj_j2k_tcp_data_destroy(&p_j2k->m_cp.tcps[l_current_tile_no]);
opj_event_msg(p_manager, EVT_INFO, opj_event_msg(p_manager, EVT_INFO,
"Image data has been updated with tile %d.\n\n", l_current_tile_no + 1); "Image data has been updated with tile %d.\n\n", l_current_tile_no + 1);
@ -10806,7 +10675,6 @@ static OPJ_BOOL opj_j2k_decode_one_tile(opj_j2k_t *p_j2k,
if (!(opj_stream_read_seek(p_stream, p_j2k->cstr_index->main_head_end + 2, if (!(opj_stream_read_seek(p_stream, p_j2k->cstr_index->main_head_end + 2,
p_manager))) { p_manager))) {
opj_event_msg(p_manager, EVT_ERROR, "Problem with seek function\n"); opj_event_msg(p_manager, EVT_ERROR, "Problem with seek function\n");
opj_free(l_current_data);
return OPJ_FALSE; return OPJ_FALSE;
} }
break; break;
@ -10818,8 +10686,6 @@ static OPJ_BOOL opj_j2k_decode_one_tile(opj_j2k_t *p_j2k,
} }
opj_free(l_current_data);
return OPJ_TRUE; return OPJ_TRUE;
} }

View File

@ -216,6 +216,8 @@ static INLINE long opj_lrintf(float f)
/* Type to use for bit-fields in internal headers */ /* Type to use for bit-fields in internal headers */
typedef unsigned int OPJ_BITFIELD; typedef unsigned int OPJ_BITFIELD;
#define OPJ_UNUSED(x) (void)x
#include "opj_inttypes.h" #include "opj_inttypes.h"
#include "opj_clock.h" #include "opj_clock.h"
#include "opj_malloc.h" #include "opj_malloc.h"
@ -243,6 +245,7 @@ typedef unsigned int OPJ_BITFIELD;
#include "t2.h" #include "t2.h"
#include "mct.h" #include "mct.h"
#include "opj_intmath.h" #include "opj_intmath.h"
#include "sparse_array.h"
#ifdef USE_JPIP #ifdef USE_JPIP
#include "cidx_manager.h" #include "cidx_manager.h"

View File

@ -0,0 +1,233 @@
/*
* 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);
}

View File

@ -0,0 +1,141 @@
/*
* 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 */

View File

@ -1601,7 +1601,9 @@ static void opj_t1_clbl_decode_processor(void* user_data, opj_tls_t* tls)
band = job->band; band = job->band;
tilec = job->tilec; tilec = job->tilec;
tccp = job->tccp; 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)) { if (!*(job->pret)) {
opj_free(job); opj_free(job);
@ -1640,7 +1642,7 @@ static void opj_t1_clbl_decode_processor(void* user_data, opj_tls_t* tls)
y += pres->y1 - pres->y0; y += pres->y1 - pres->y0;
} }
datap = t1->data; datap = cblk->decoded_data ? cblk->decoded_data : t1->data;
cblk_w = t1->w; cblk_w = t1->w;
cblk_h = t1->h; cblk_h = t1->h;
@ -1665,7 +1667,35 @@ static void opj_t1_clbl_decode_processor(void* user_data, opj_tls_t* tls)
} }
} }
} }
if (cblk->decoded_data) {
if (tccp->qmfbid == 1) { 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_INT32* OPJ_RESTRICT tiledp = &tilec->data[(OPJ_UINT32)y * tile_w +
(OPJ_UINT32)x]; (OPJ_UINT32)x];
for (j = 0; j < cblk_h; ++j) { for (j = 0; j < cblk_h; ++j) {
@ -1724,7 +1754,6 @@ void opj_t1_decode_cblks(opj_tcd_t* tcd,
for (precno = 0; precno < res->pw * res->ph; ++precno) { for (precno = 0; precno < res->pw * res->ph; ++precno) {
opj_tcd_precinct_t* precinct = &band->precincts[precno]; opj_tcd_precinct_t* precinct = &band->precincts[precno];
OPJ_BOOL skip_precinct = OPJ_FALSE;
if (!opj_tcd_is_subband_area_of_interest(tcd, if (!opj_tcd_is_subband_area_of_interest(tcd,
tilec->compno, tilec->compno,
@ -1734,17 +1763,16 @@ void opj_t1_decode_cblks(opj_tcd_t* tcd,
(OPJ_UINT32)precinct->y0, (OPJ_UINT32)precinct->y0,
(OPJ_UINT32)precinct->x1, (OPJ_UINT32)precinct->x1,
(OPJ_UINT32)precinct->y1)) { (OPJ_UINT32)precinct->y1)) {
skip_precinct = OPJ_TRUE; continue;
/* TODO: do a continue here once the below 0 initialization */
/* of tiledp is removed */
} }
for (cblkno = 0; cblkno < precinct->cw * precinct->ch; ++cblkno) { for (cblkno = 0; cblkno < precinct->cw * precinct->ch; ++cblkno) {
opj_tcd_cblk_dec_t* cblk = &precinct->cblks.dec[cblkno]; opj_tcd_cblk_dec_t* cblk = &precinct->cblks.dec[cblkno];
opj_t1_cblk_decode_processing_job_t* job; opj_t1_cblk_decode_processing_job_t* job;
if (skip_precinct || assert(cblk->decoded_data == NULL);
!opj_tcd_is_subband_area_of_interest(tcd,
if (!opj_tcd_is_subband_area_of_interest(tcd,
tilec->compno, tilec->compno,
resno, resno,
band->bandno, band->bandno,
@ -1752,34 +1780,30 @@ void opj_t1_decode_cblks(opj_tcd_t* tcd,
(OPJ_UINT32)cblk->y0, (OPJ_UINT32)cblk->y0,
(OPJ_UINT32)cblk->x1, (OPJ_UINT32)cblk->x1,
(OPJ_UINT32)cblk->y1)) { (OPJ_UINT32)cblk->y1)) {
continue;
}
/* TODO: remove this once we don't iterate over */ if (!tcd->whole_tile_decoding) {
/* 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);
OPJ_UINT32 cblk_w = (OPJ_UINT32)(cblk->x1 - cblk->x0); OPJ_UINT32 cblk_w = (OPJ_UINT32)(cblk->x1 - cblk->x0);
OPJ_UINT32 cblk_h = (OPJ_UINT32)(cblk->y1 - cblk->y0); OPJ_UINT32 cblk_h = (OPJ_UINT32)(cblk->y1 - cblk->y0);
if (cblk_w == 0 || cblk_h == 0) {
if (band->bandno & 1) {
opj_tcd_resolution_t* pres = &tilec->resolutions[resno - 1];
x += pres->x1 - pres->x0;
}
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));
}
continue; continue;
} }
/* 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;
}
}
job = (opj_t1_cblk_decode_processing_job_t*) opj_calloc(1, job = (opj_t1_cblk_decode_processing_job_t*) opj_calloc(1,
sizeof(opj_t1_cblk_decode_processing_job_t)); sizeof(opj_t1_cblk_decode_processing_job_t));
@ -1827,6 +1851,7 @@ static OPJ_BOOL opj_t1_decode_cblk(opj_t1_t *t1,
OPJ_BYTE* cblkdata = NULL; OPJ_BYTE* cblkdata = NULL;
OPJ_UINT32 cblkdataindex = 0; OPJ_UINT32 cblkdataindex = 0;
OPJ_BYTE type = T1_TYPE_MQ; /* BYPASS mode */ OPJ_BYTE type = T1_TYPE_MQ; /* BYPASS mode */
OPJ_INT32* original_t1_data = NULL;
mqc->lut_ctxno_zc_orient = lut_ctxno_zc + (orient << 9); mqc->lut_ctxno_zc_orient = lut_ctxno_zc + (orient << 9);
@ -1893,6 +1918,13 @@ static OPJ_BOOL opj_t1_decode_cblk(opj_t1_t *t1,
cblkdata = cblk->chunks[0].data; 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) { for (segno = 0; segno < cblk->real_num_segs; ++segno) {
opj_tcd_seg_t *seg = &cblk->segs[segno]; opj_tcd_seg_t *seg = &cblk->segs[segno];
@ -1972,6 +2004,11 @@ static OPJ_BOOL opj_t1_decode_cblk(opj_t1_t *t1,
} }
} }
/* Restore original t1->data is needed */
if (cblk->decoded_data) {
t1->data = original_t1_data;
}
return OPJ_TRUE; return OPJ_TRUE;
} }

View File

@ -190,6 +190,10 @@ static OPJ_BOOL opj_tcd_rate_allocate_encode(opj_tcd_t *p_tcd,
opj_codestream_info_t *p_cstr_info, opj_codestream_info_t *p_cstr_info,
opj_event_mgr_t *p_manager); opj_event_mgr_t *p_manager);
static OPJ_BOOL opj_tcd_is_whole_tilecomp_decoding(opj_tcd_t *tcd,
OPJ_UINT32 compno);
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
/** /**
@ -679,7 +683,7 @@ OPJ_BOOL opj_alloc_tile_component_data(opj_tcd_tilecomp_t *l_tilec)
((l_tilec->data_size_needed > l_tilec->data_size) && ((l_tilec->data_size_needed > l_tilec->data_size) &&
(l_tilec->ownsData == OPJ_FALSE))) { (l_tilec->ownsData == OPJ_FALSE))) {
l_tilec->data = (OPJ_INT32 *) opj_image_data_alloc(l_tilec->data_size_needed); 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; return OPJ_FALSE;
} }
/*fprintf(stderr, "tAllocate data of tilec (int): %d x OPJ_UINT32n",l_data_size);*/ /*fprintf(stderr, "tAllocate data of tilec (int): %d x OPJ_UINT32n",l_data_size);*/
@ -794,6 +798,15 @@ static INLINE OPJ_BOOL opj_tcd_init_tile(opj_tcd_t *p_tcd, OPJ_UINT32 p_tile_no,
l_tilec->compno = compno; 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);*/ /*fprintf(stderr, "\tTile compo border = %d,%d,%d,%d\n", l_tilec->x0, l_tilec->y0,l_tilec->x1,l_tilec->y1);*/
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;
} else {
l_tilec->minimum_num_resolutions = l_tccp->numresolutions -
l_cp->m_specific_param.m_dec.m_reduce;
}
if (isEncoder) {
/* compute l_data_size with overflow check */ /* compute l_data_size with overflow check */
l_data_size = (OPJ_UINT32)(l_tilec->x1 - l_tilec->x0); 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 */ /* issue 733, l_data_size == 0U, probably something wrong should be checked before getting here */
@ -810,23 +823,20 @@ static INLINE OPJ_BOOL opj_tcd_init_tile(opj_tcd_t *p_tcd, OPJ_UINT32 p_tile_no,
return OPJ_FALSE; return OPJ_FALSE;
} }
l_data_size = l_data_size * (OPJ_UINT32)sizeof(OPJ_UINT32); 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;
} else {
l_tilec->minimum_num_resolutions = l_tccp->numresolutions -
l_cp->m_specific_param.m_dec.m_reduce;
}
l_tilec->data_size_needed = l_data_size; 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;
} }
l_data_size = l_tilec->numresolutions * (OPJ_UINT32)sizeof( l_data_size = l_tilec->numresolutions * (OPJ_UINT32)sizeof(
opj_tcd_resolution_t); 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) { if (l_tilec->resolutions == 00) {
l_tilec->resolutions = (opj_tcd_resolution_t *) opj_malloc(l_data_size); l_tilec->resolutions = (opj_tcd_resolution_t *) opj_malloc(l_data_size);
if (! l_tilec->resolutions) { if (! l_tilec->resolutions) {
@ -875,6 +885,28 @@ static INLINE OPJ_BOOL opj_tcd_init_tile(opj_tcd_t *p_tcd, OPJ_UINT32 p_tile_no,
l_res->y0 = opj_int_ceildivpow2(l_tilec->y0, (OPJ_INT32)l_level_no); 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->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); 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);*/ /*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) */ /* p. 35, table A-23, ISO/IEC FDIS154444-1 : 2000 (18 august 2000) */
l_pdx = l_tccp->prcw[resno]; l_pdx = l_tccp->prcw[resno];
@ -1249,6 +1281,9 @@ static OPJ_BOOL opj_tcd_code_block_dec_allocate(opj_tcd_cblk_dec_t *
OPJ_UINT32 l_numchunksalloc = p_code_block->numchunksalloc; OPJ_UINT32 l_numchunksalloc = p_code_block->numchunksalloc;
OPJ_UINT32 i; 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)); memset(p_code_block, 0, sizeof(opj_tcd_cblk_dec_t));
p_code_block->segs = l_segs; p_code_block->segs = l_segs;
p_code_block->m_current_max_segs = l_current_max_segs; p_code_block->m_current_max_segs = l_current_max_segs;
@ -1262,7 +1297,8 @@ static OPJ_BOOL opj_tcd_code_block_dec_allocate(opj_tcd_cblk_dec_t *
return OPJ_TRUE; 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 i;
OPJ_UINT32 l_data_size = 0; OPJ_UINT32 l_data_size = 0;
@ -1288,8 +1324,13 @@ OPJ_UINT32 opj_tcd_get_decoded_tile_size(opj_tcd_t *p_tcd)
} }
l_res = l_tile_comp->resolutions + l_tile_comp->minimum_num_resolutions - 1; l_res = l_tile_comp->resolutions + l_tile_comp->minimum_num_resolutions - 1;
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_temp = (OPJ_UINT32)((l_res->x1 - l_res->x0) * (l_res->y1 -
l_res->y0)); /* x1*y1 can't overflow */ l_res->y0)); /* x1*y1 can't overflow */
}
if (l_size_comp && UINT_MAX / l_size_comp < l_temp) { if (l_size_comp && UINT_MAX / l_size_comp < l_temp) {
return UINT_MAX; return UINT_MAX;
} }
@ -1401,10 +1442,10 @@ OPJ_BOOL opj_tcd_encode_tile(opj_tcd_t *p_tcd,
} }
OPJ_BOOL opj_tcd_decode_tile(opj_tcd_t *p_tcd, OPJ_BOOL opj_tcd_decode_tile(opj_tcd_t *p_tcd,
OPJ_UINT32 decoded_x0, OPJ_UINT32 win_x0,
OPJ_UINT32 decoded_y0, OPJ_UINT32 win_y0,
OPJ_UINT32 decoded_x1, OPJ_UINT32 win_x1,
OPJ_UINT32 decoded_y1, OPJ_UINT32 win_y1,
OPJ_BYTE *p_src, OPJ_BYTE *p_src,
OPJ_UINT32 p_max_length, OPJ_UINT32 p_max_length,
OPJ_UINT32 p_tile_no, OPJ_UINT32 p_tile_no,
@ -1413,12 +1454,66 @@ OPJ_BOOL opj_tcd_decode_tile(opj_tcd_t *p_tcd,
) )
{ {
OPJ_UINT32 l_data_read; OPJ_UINT32 l_data_read;
OPJ_UINT32 compno;
p_tcd->tcd_tileno = p_tile_no; p_tcd->tcd_tileno = p_tile_no;
p_tcd->tcp = &(p_tcd->cp->tcps[p_tile_no]); p_tcd->tcp = &(p_tcd->cp->tcps[p_tile_no]);
p_tcd->decoded_x0 = decoded_x0; p_tcd->win_x0 = win_x0;
p_tcd->decoded_y0 = decoded_y0; p_tcd->win_y0 = win_y0;
p_tcd->decoded_x1 = decoded_x1; p_tcd->win_x1 = win_x1;
p_tcd->decoded_y1 = decoded_y1; 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 */ #ifdef TODO_MSD /* FIXME */
/* INDEX >> */ /* INDEX >> */
@ -1461,6 +1556,42 @@ OPJ_BOOL opj_tcd_decode_tile(opj_tcd_t *p_tcd,
} }
/* FIXME _ProfStop(PGROUP_T1); */ /* 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---------------------*/ /*----------------DWT---------------------*/
/* FIXME _ProfStart(PGROUP_DWT); */ /* FIXME _ProfStart(PGROUP_DWT); */
@ -1502,7 +1633,7 @@ OPJ_BOOL opj_tcd_update_tile_data(opj_tcd_t *p_tcd,
OPJ_UINT32 l_size_comp, l_remaining; OPJ_UINT32 l_size_comp, l_remaining;
OPJ_UINT32 l_stride, l_width, l_height; 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) { if (l_data_size == UINT_MAX || l_data_size > p_dest_length) {
return OPJ_FALSE; return OPJ_FALSE;
} }
@ -1511,12 +1642,23 @@ OPJ_BOOL opj_tcd_update_tile_data(opj_tcd_t *p_tcd,
l_img_comp = p_tcd->image->comps; l_img_comp = p_tcd->image->comps;
for (i = 0; i < p_tcd->image->numcomps; ++i) { 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_size_comp = l_img_comp->prec >> 3; /*(/ 8)*/
l_remaining = l_img_comp->prec & 7; /* (%8) */ l_remaining = l_img_comp->prec & 7; /* (%8) */
l_res = l_tilec->resolutions + l_img_comp->resno_decoded; l_res = l_tilec->resolutions + l_img_comp->resno_decoded;
if (p_tcd->whole_tile_decoding) {
l_width = (OPJ_UINT32)(l_res->x1 - l_res->x0); l_width = (OPJ_UINT32)(l_res->x1 - l_res->x0);
l_height = (OPJ_UINT32)(l_res->y1 - l_res->y0); l_height = (OPJ_UINT32)(l_res->y1 - l_res->y0);
l_stride = (OPJ_UINT32)(l_tilec->x1 - l_tilec->x0) - l_width; 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) { if (l_remaining) {
++l_size_comp; ++l_size_comp;
@ -1529,7 +1671,7 @@ OPJ_BOOL opj_tcd_update_tile_data(opj_tcd_t *p_tcd,
switch (l_size_comp) { switch (l_size_comp) {
case 1: { case 1: {
OPJ_CHAR * l_dest_ptr = (OPJ_CHAR *) p_dest; 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) { if (l_img_comp->sgnd) {
for (j = 0; j < l_height; ++j) { for (j = 0; j < l_height; ++j) {
@ -1551,7 +1693,7 @@ OPJ_BOOL opj_tcd_update_tile_data(opj_tcd_t *p_tcd,
} }
break; break;
case 2: { 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; OPJ_INT16 * l_dest_ptr = (OPJ_INT16 *) p_dest;
if (l_img_comp->sgnd) { if (l_img_comp->sgnd) {
@ -1579,7 +1721,7 @@ OPJ_BOOL opj_tcd_update_tile_data(opj_tcd_t *p_tcd,
break; break;
case 4: { case 4: {
OPJ_INT32 * l_dest_ptr = (OPJ_INT32 *) p_dest; 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) { for (j = 0; j < l_height; ++j) {
memcpy(l_dest_ptr, l_src_ptr, l_width * sizeof(OPJ_INT32)); memcpy(l_dest_ptr, l_src_ptr, l_width * sizeof(OPJ_INT32));
@ -1674,6 +1816,9 @@ static void opj_tcd_free_tile(opj_tcd_t *p_tcd)
l_tile_comp->data_size = 0; l_tile_comp->data_size = 0;
l_tile_comp->data_size_needed = 0; l_tile_comp->data_size_needed = 0;
} }
opj_aligned_free(l_tile_comp->data_win);
++l_tile_comp; ++l_tile_comp;
} }
@ -1764,18 +1909,6 @@ static OPJ_BOOL opj_tcd_dwt_decode(opj_tcd_t *p_tcd)
opj_image_comp_t * l_img_comp = p_tcd->image->comps; opj_image_comp_t * l_img_comp = p_tcd->image->comps;
for (compno = 0; compno < l_tile->numcomps; compno++) { 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 (l_tccp->qmfbid == 1) {
if (! opj_dwt_decode(p_tcd, l_tile_comp, if (! opj_dwt_decode(p_tcd, l_tile_comp,
@ -1796,6 +1929,7 @@ static OPJ_BOOL opj_tcd_dwt_decode(opj_tcd_t *p_tcd)
return OPJ_TRUE; return OPJ_TRUE;
} }
static OPJ_BOOL opj_tcd_mct_decode(opj_tcd_t *p_tcd, opj_event_mgr_t *p_manager) 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; opj_tcd_tile_t * l_tile = p_tcd->tcd_image->tiles;
@ -1807,17 +1941,40 @@ static OPJ_BOOL opj_tcd_mct_decode(opj_tcd_t *p_tcd, opj_event_mgr_t *p_manager)
return OPJ_TRUE; return OPJ_TRUE;
} }
l_samples = (OPJ_UINT32)((l_tile_comp->x1 - l_tile_comp->x0) * if (p_tcd->whole_tile_decoding) {
(l_tile_comp->y1 - l_tile_comp->y0)); /* 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) { 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 */ /* testcase 1336.pdf.asan.47.376 */
if ((l_tile->comps[0].x1 - l_tile->comps[0].x0) * (l_tile->comps[0].y1 - if (p_tcd->image->comps[0].resno_decoded !=
l_tile->comps[0].y0) < (OPJ_INT32)l_samples || p_tcd->image->comps[1].resno_decoded ||
(l_tile->comps[1].x1 - l_tile->comps[1].x0) * (l_tile->comps[1].y1 - p_tcd->image->comps[0].resno_decoded !=
l_tile->comps[1].y0) < (OPJ_INT32)l_samples || p_tcd->image->comps[2].resno_decoded ||
(l_tile->comps[2].x1 - l_tile->comps[2].x0) * (l_tile->comps[2].y1 - (res_comp1->x1 - res_comp1->x0) * (res_comp1->y1 -
l_tile->comps[2].y0) < (OPJ_INT32)l_samples) { 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, opj_event_msg(p_manager, EVT_ERROR,
"Tiles don't all have the same dimension. Skip the MCT step.\n"); "Tiles don't all have the same dimension. Skip the MCT step.\n");
return OPJ_FALSE; return OPJ_FALSE;
@ -1834,7 +1991,11 @@ static OPJ_BOOL opj_tcd_mct_decode(opj_tcd_t *p_tcd, opj_event_mgr_t *p_manager)
} }
for (i = 0; i < l_tile->numcomps; ++i) { for (i = 0; i < l_tile->numcomps; ++i) {
if (p_tcd->whole_tile_decoding) {
l_data[i] = (OPJ_BYTE*) l_tile_comp->data; l_data[i] = (OPJ_BYTE*) l_tile_comp->data;
} else {
l_data[i] = (OPJ_BYTE*) l_tile_comp->data_win;
}
++l_tile_comp; ++l_tile_comp;
} }
@ -1855,15 +2016,29 @@ static OPJ_BOOL opj_tcd_mct_decode(opj_tcd_t *p_tcd, opj_event_mgr_t *p_manager)
opj_free(l_data); opj_free(l_data);
} else { } else {
if (l_tcp->tccps->qmfbid == 1) { if (l_tcp->tccps->qmfbid == 1) {
if (p_tcd->whole_tile_decoding) {
opj_mct_decode(l_tile->comps[0].data, opj_mct_decode(l_tile->comps[0].data,
l_tile->comps[1].data, l_tile->comps[1].data,
l_tile->comps[2].data, l_tile->comps[2].data,
l_samples); l_samples);
} else { } 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 {
if (p_tcd->whole_tile_decoding) {
opj_mct_decode_real((OPJ_FLOAT32*)l_tile->comps[0].data, opj_mct_decode_real((OPJ_FLOAT32*)l_tile->comps[0].data,
(OPJ_FLOAT32*)l_tile->comps[1].data, (OPJ_FLOAT32*)l_tile->comps[1].data,
(OPJ_FLOAT32*)l_tile->comps[2].data, (OPJ_FLOAT32*)l_tile->comps[2].data,
l_samples); 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 { } else {
@ -1896,12 +2071,24 @@ static OPJ_BOOL opj_tcd_dc_level_shift_decode(opj_tcd_t *p_tcd)
for (compno = 0; compno < l_tile->numcomps; compno++) { for (compno = 0; compno < l_tile->numcomps; compno++) {
l_res = l_tile_comp->resolutions + l_img_comp->resno_decoded; l_res = l_tile_comp->resolutions + l_img_comp->resno_decoded;
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_width = (OPJ_UINT32)(l_res->x1 - l_res->x0);
l_height = (OPJ_UINT32)(l_res->y1 - l_res->y0); l_height = (OPJ_UINT32)(l_res->y1 - l_res->y0);
l_stride = (OPJ_UINT32)(l_tile_comp->x1 - l_tile_comp->x0) - l_width; 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 || assert(l_height == 0 ||
l_width + l_stride <= l_tile_comp->data_size / l_height); /*MUPDF*/ l_width + l_stride <= l_tile_comp->data_size / l_height); /*MUPDF*/
}
if (l_img_comp->sgnd) { if (l_img_comp->sgnd) {
l_min = -(1 << (l_img_comp->prec - 1)); l_min = -(1 << (l_img_comp->prec - 1));
@ -1911,7 +2098,6 @@ static OPJ_BOOL opj_tcd_dc_level_shift_decode(opj_tcd_t *p_tcd)
l_max = (OPJ_INT32)((1U << 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) { if (l_tccp->qmfbid == 1) {
for (j = 0; j < l_height; ++j) { for (j = 0; j < l_height; ++j) {
@ -1981,6 +2167,9 @@ static void opj_tcd_code_block_dec_deallocate(opj_tcd_precinct_t * p_precinct)
l_code_block->chunks = 00; l_code_block->chunks = 00;
} }
opj_free(l_code_block->decoded_data);
l_code_block->decoded_data = NULL;
++l_code_block; ++l_code_block;
} }
@ -2396,16 +2585,16 @@ OPJ_BOOL opj_tcd_is_subband_area_of_interest(opj_tcd_t *tcd,
/* with the tile coordinates */ /* with the tile coordinates */
OPJ_UINT32 tcx0 = opj_uint_max( OPJ_UINT32 tcx0 = opj_uint_max(
(OPJ_UINT32)tilec->x0, (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 tcy0 = opj_uint_max(
(OPJ_UINT32)tilec->y0, (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 tcx1 = opj_uint_min(
(OPJ_UINT32)tilec->x1, (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 tcy1 = opj_uint_min(
(OPJ_UINT32)tilec->y1, (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 */ /* Compute number of decomposition for this band. See table F-1 */
OPJ_UINT32 nb = (resno == 0) ? OPJ_UINT32 nb = (resno == 0) ?
tilec->numresolutions - 1 : tilec->numresolutions - 1 :
@ -2452,3 +2641,44 @@ OPJ_BOOL opj_tcd_is_subband_area_of_interest(opj_tcd_t *tcd,
#endif #endif
return intersects; 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)));
}

View File

@ -134,6 +134,8 @@ typedef struct opj_tcd_cblk_dec {
OPJ_UINT32 m_current_max_segs; /* allocated number of segs[] items */ OPJ_UINT32 m_current_max_segs; /* allocated number of segs[] items */
OPJ_UINT32 numchunks; /* Number of valid chunks items */ OPJ_UINT32 numchunks; /* Number of valid chunks items */
OPJ_UINT32 numchunksalloc; /* Number of chunks item allocated */ 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; } opj_tcd_cblk_dec_t;
/** Precinct structure */ /** Precinct structure */
@ -175,6 +177,12 @@ typedef struct opj_tcd_resolution {
OPJ_UINT32 numbands; OPJ_UINT32 numbands;
/* subband information */ /* subband information */
opj_tcd_band_t bands[3]; 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; } opj_tcd_resolution_t;
/** Tile-component structure */ /** Tile-component structure */
@ -191,7 +199,8 @@ typedef struct opj_tcd_tilecomp {
opj_tcd_resolution_t *resolutions; opj_tcd_resolution_t *resolutions;
/* size of data for resolutions (in bytes) */ /* size of data for resolutions (in bytes) */
OPJ_UINT32 resolutions_size; 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; OPJ_INT32 *data;
/* if true, then need to free after usage, otherwise do not free */ /* if true, then need to free after usage, otherwise do not free */
OPJ_BOOL ownsData; OPJ_BOOL ownsData;
@ -199,6 +208,15 @@ typedef struct opj_tcd_tilecomp {
OPJ_UINT32 data_size_needed; OPJ_UINT32 data_size_needed;
/* size of the data of the component */ /* size of the data of the component */
OPJ_UINT32 data_size; 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 */ /* add fixed_quality */
OPJ_INT32 numpix; OPJ_INT32 numpix;
} opj_tcd_tilecomp_t; } opj_tcd_tilecomp_t;
@ -256,10 +274,12 @@ typedef struct opj_tcd {
/** Thread pool */ /** Thread pool */
opj_thread_pool_t* thread_pool; opj_thread_pool_t* thread_pool;
/** Coordinates of the window of interest, in grid reference space */ /** Coordinates of the window of interest, in grid reference space */
OPJ_UINT32 decoded_x0; OPJ_UINT32 win_x0;
OPJ_UINT32 decoded_y0; OPJ_UINT32 win_y0;
OPJ_UINT32 decoded_x1; OPJ_UINT32 win_x1;
OPJ_UINT32 decoded_y1; 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; } opj_tcd_t;
/** @name Exported functions */ /** @name Exported functions */
@ -331,7 +351,8 @@ OPJ_BOOL opj_tcd_rateallocate(opj_tcd_t *tcd,
/** /**
* Gets the maximum tile size that will be taken by the tile once decoded. * 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. * Encodes a tile from the raw image into the given buffer.
@ -356,10 +377,10 @@ OPJ_BOOL opj_tcd_encode_tile(opj_tcd_t *p_tcd,
/** /**
Decode a tile from a buffer into a raw image Decode a tile from a buffer into a raw image
@param tcd TCD handle @param tcd TCD handle
@param decoded_x0 Upper left x of region to decode (in grid coordinates) @param win_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 win_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 win_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_y1 Lower right y of region to decode (in grid coordinates)
@param src Source buffer @param src Source buffer
@param len Length of source buffer @param len Length of source buffer
@param tileno Number that identifies one of the tiles to be decoded @param tileno Number that identifies one of the tiles to be decoded
@ -367,10 +388,10 @@ Decode a tile from a buffer into a raw image
@param manager the event manager. @param manager the event manager.
*/ */
OPJ_BOOL opj_tcd_decode_tile(opj_tcd_t *tcd, OPJ_BOOL opj_tcd_decode_tile(opj_tcd_t *tcd,
OPJ_UINT32 decoded_x0, OPJ_UINT32 win_x0,
OPJ_UINT32 decoded_y0, OPJ_UINT32 win_y0,
OPJ_UINT32 decoded_x1, OPJ_UINT32 win_x1,
OPJ_UINT32 decoded_y1, OPJ_UINT32 win_y1,
OPJ_BYTE *src, OPJ_BYTE *src,
OPJ_UINT32 len, OPJ_UINT32 len,
OPJ_UINT32 tileno, OPJ_UINT32 tileno,
@ -427,7 +448,7 @@ void opj_tcd_reinit_segment(opj_tcd_seg_t* seg);
/** Returns whether a sub-band region contributes to the area of interest /** 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 tcd TCD handle.
* @param compno Component number * @param compno Component number
@ -449,7 +470,6 @@ OPJ_BOOL opj_tcd_is_subband_area_of_interest(opj_tcd_t *tcd,
OPJ_UINT32 x1, OPJ_UINT32 x1,
OPJ_UINT32 y1); OPJ_UINT32 y1);
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
/*@}*/ /*@}*/

View File

@ -0,0 +1,148 @@
/*
* 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;
}