summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEven Rouault <even.rouault@spatialys.com>2024-07-01 13:03:32 +0200
committerEven Rouault <even.rouault@spatialys.com>2024-07-01 13:03:32 +0200
commited3a818370447c0572d016a7f55744c732d87973 (patch)
tree92d555c3e57d25bad4f22885e629e7dac9ba14a8 /src
parent206ede76e9550bf6584b669b2aa35f0cab462775 (diff)
Use TLM markers to optimize opj_decode() (on a subset of tiles)
Diffstat (limited to 'src')
-rw-r--r--src/lib/openjp2/j2k.c126
-rw-r--r--src/lib/openjp2/j2k.h10
2 files changed, 136 insertions, 0 deletions
diff --git a/src/lib/openjp2/j2k.c b/src/lib/openjp2/j2k.c
index 55ef0191..1e6536aa 100644
--- a/src/lib/openjp2/j2k.c
+++ b/src/lib/openjp2/j2k.c
@@ -9366,6 +9366,9 @@ void opj_j2k_destroy(opj_j2k_t *p_j2k)
opj_free(p_j2k->m_specific_param.m_decoder.m_tlm.m_tile_part_infos);
p_j2k->m_specific_param.m_decoder.m_tlm.m_tile_part_infos = NULL;
+ opj_free(p_j2k->m_specific_param.m_decoder.m_intersecting_tile_parts_offset);
+ p_j2k->m_specific_param.m_decoder.m_intersecting_tile_parts_offset = NULL;
+
} else {
if (p_j2k->m_specific_param.m_encoder.m_encoded_tile_data) {
@@ -9716,6 +9719,39 @@ OPJ_BOOL opj_j2k_read_tile_header(opj_j2k_t * p_j2k,
while ((!p_j2k->m_specific_param.m_decoder.m_can_decode) &&
(l_current_marker != J2K_MS_EOC)) {
+ if (p_j2k->m_specific_param.m_decoder.m_num_intersecting_tile_parts > 0 &&
+ p_j2k->m_specific_param.m_decoder.m_idx_intersecting_tile_parts <
+ p_j2k->m_specific_param.m_decoder.m_num_intersecting_tile_parts) {
+ OPJ_OFF_T next_tp_sot_pos;
+
+ next_tp_sot_pos =
+ p_j2k->m_specific_param.m_decoder.m_intersecting_tile_parts_offset[p_j2k->m_specific_param.m_decoder.m_idx_intersecting_tile_parts];
+ ++p_j2k->m_specific_param.m_decoder.m_idx_intersecting_tile_parts;
+ if (!(opj_stream_read_seek(p_stream,
+ next_tp_sot_pos,
+ p_manager))) {
+ opj_event_msg(p_manager, EVT_ERROR, "Problem with seek function\n");
+ return OPJ_FALSE;
+ }
+
+ /* Try to read 2 bytes (the marker ID) from stream and copy them into the buffer */
+ if (opj_stream_read_data(p_stream,
+ p_j2k->m_specific_param.m_decoder.m_header_data, 2, p_manager) != 2) {
+ opj_event_msg(p_manager, EVT_ERROR, "Stream too short\n");
+ return OPJ_FALSE;
+ }
+
+ /* Read 2 bytes from the buffer as the marker ID */
+ opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data,
+ &l_current_marker,
+ 2);
+
+ if (l_current_marker != J2K_MS_SOT) {
+ opj_event_msg(p_manager, EVT_ERROR, "Did not get expected SOT marker\n");
+ return OPJ_FALSE;
+ }
+ }
+
/* Try to read until the Start Of Data is detected */
while (l_current_marker != J2K_MS_SOD) {
@@ -11875,6 +11911,18 @@ static OPJ_BOOL opj_j2k_are_all_used_components_decoded(opj_j2k_t *p_j2k,
return OPJ_TRUE;
}
+static int CompareOffT(const void* a, const void* b)
+{
+ const OPJ_OFF_T offA = *(const OPJ_OFF_T*)a;
+ const OPJ_OFF_T offB = *(const OPJ_OFF_T*)b;
+ if (offA < offB) {
+ return -1;
+ }
+ if (offA == offB) {
+ return 0;
+ }
+ return 1;
+}
static OPJ_BOOL opj_j2k_decode_tiles(opj_j2k_t *p_j2k,
opj_stream_private_t *p_stream,
@@ -11885,6 +11933,7 @@ static OPJ_BOOL opj_j2k_decode_tiles(opj_j2k_t *p_j2k,
OPJ_INT32 l_tile_x0, l_tile_y0, l_tile_x1, l_tile_y1;
OPJ_UINT32 l_nb_comps;
OPJ_UINT32 nr_tiles = 0;
+ OPJ_OFF_T end_pos = 0;
/* Particular case for whole single tile decoding */
/* We can avoid allocating intermediate tile buffers */
@@ -11927,6 +11976,77 @@ static OPJ_BOOL opj_j2k_decode_tiles(opj_j2k_t *p_j2k,
return OPJ_TRUE;
}
+ p_j2k->m_specific_param.m_decoder.m_num_intersecting_tile_parts = 0;
+ p_j2k->m_specific_param.m_decoder.m_idx_intersecting_tile_parts = 0;
+ opj_free(p_j2k->m_specific_param.m_decoder.m_intersecting_tile_parts_offset);
+ p_j2k->m_specific_param.m_decoder.m_intersecting_tile_parts_offset = NULL;
+
+ /* If the area to decode only intersects a subset of tiles, and we have
+ * valid TLM information, then use it to plan the tilepart offsets to
+ * seek to.
+ */
+ if (!(p_j2k->m_specific_param.m_decoder.m_start_tile_x == 0 &&
+ p_j2k->m_specific_param.m_decoder.m_start_tile_y == 0 &&
+ p_j2k->m_specific_param.m_decoder.m_end_tile_x == p_j2k->m_cp.tw &&
+ p_j2k->m_specific_param.m_decoder.m_end_tile_y == p_j2k->m_cp.th) &&
+ !p_j2k->m_specific_param.m_decoder.m_tlm.m_is_invalid &&
+ opj_stream_has_seek(p_stream)) {
+ OPJ_UINT32 m_num_intersecting_tile_parts = 0;
+
+ OPJ_UINT32 j;
+ for (j = 0; j < p_j2k->m_cp.tw * p_j2k->m_cp.th; ++j) {
+ if (p_j2k->cstr_index->tile_index[j].nb_tps > 0 &&
+ p_j2k->cstr_index->tile_index[j].tp_index[
+ p_j2k->cstr_index->tile_index[j].nb_tps - 1].end_pos > end_pos) {
+ end_pos = p_j2k->cstr_index->tile_index[j].tp_index[
+ p_j2k->cstr_index->tile_index[j].nb_tps - 1].end_pos;
+ }
+ }
+
+ for (j = p_j2k->m_specific_param.m_decoder.m_start_tile_y;
+ j < p_j2k->m_specific_param.m_decoder.m_end_tile_y; ++j) {
+ OPJ_UINT32 i;
+ for (i = p_j2k->m_specific_param.m_decoder.m_start_tile_x;
+ i < p_j2k->m_specific_param.m_decoder.m_end_tile_x; ++i) {
+ const OPJ_UINT32 tile_number = j * p_j2k->m_cp.tw + i;
+ m_num_intersecting_tile_parts +=
+ p_j2k->cstr_index->tile_index[tile_number].nb_tps;
+ }
+ }
+
+ p_j2k->m_specific_param.m_decoder.m_intersecting_tile_parts_offset =
+ (OPJ_OFF_T*)
+ opj_malloc(m_num_intersecting_tile_parts * sizeof(OPJ_OFF_T));
+ if (m_num_intersecting_tile_parts > 0 &&
+ p_j2k->m_specific_param.m_decoder.m_intersecting_tile_parts_offset) {
+ OPJ_UINT32 idx = 0;
+ for (j = p_j2k->m_specific_param.m_decoder.m_start_tile_y;
+ j < p_j2k->m_specific_param.m_decoder.m_end_tile_y; ++j) {
+ OPJ_UINT32 i;
+ for (i = p_j2k->m_specific_param.m_decoder.m_start_tile_x;
+ i < p_j2k->m_specific_param.m_decoder.m_end_tile_x; ++i) {
+ const OPJ_UINT32 tile_number = j * p_j2k->m_cp.tw + i;
+ OPJ_UINT32 k;
+ for (k = 0; k < p_j2k->cstr_index->tile_index[tile_number].nb_tps; ++k) {
+ const OPJ_OFF_T next_tp_sot_pos =
+ p_j2k->cstr_index->tile_index[tile_number].tp_index[k].start_pos;
+ p_j2k->m_specific_param.m_decoder.m_intersecting_tile_parts_offset[idx] =
+ next_tp_sot_pos;
+ ++idx;
+ }
+ }
+ }
+
+ p_j2k->m_specific_param.m_decoder.m_num_intersecting_tile_parts = idx;
+
+ /* Sort by increasing offset */
+ qsort(p_j2k->m_specific_param.m_decoder.m_intersecting_tile_parts_offset,
+ p_j2k->m_specific_param.m_decoder.m_num_intersecting_tile_parts,
+ sizeof(OPJ_OFF_T),
+ CompareOffT);
+ }
+ }
+
for (;;) {
if (p_j2k->m_cp.tw == 1 && p_j2k->m_cp.th == 1 &&
p_j2k->m_cp.tcps[0].m_data != NULL) {
@@ -11986,6 +12106,12 @@ static OPJ_BOOL opj_j2k_decode_tiles(opj_j2k_t *p_j2k,
if (++nr_tiles == p_j2k->m_cp.th * p_j2k->m_cp.tw) {
break;
}
+ if (p_j2k->m_specific_param.m_decoder.m_num_intersecting_tile_parts > 0 &&
+ p_j2k->m_specific_param.m_decoder.m_idx_intersecting_tile_parts ==
+ p_j2k->m_specific_param.m_decoder.m_num_intersecting_tile_parts) {
+ opj_stream_seek(p_stream, end_pos + 2, p_manager);
+ break;
+ }
}
if (! opj_j2k_are_all_used_components_decoded(p_j2k, p_manager)) {
diff --git a/src/lib/openjp2/j2k.h b/src/lib/openjp2/j2k.h
index 9ca5f547..bcf70a41 100644
--- a/src/lib/openjp2/j2k.h
+++ b/src/lib/openjp2/j2k.h
@@ -519,6 +519,16 @@ typedef struct opj_j2k_dec {
opj_j2k_tlm_info_t m_tlm;
+ /** Below if used when there's TLM information available and we use
+ * opj_set_decoded_area() to a subset of all tiles.
+ */
+ /* Current index in m_intersecting_tile_parts_offset[] to seek to */
+ OPJ_UINT32 m_idx_intersecting_tile_parts;
+ /* Number of elements of m_intersecting_tile_parts_offset[] */
+ OPJ_UINT32 m_num_intersecting_tile_parts;
+ /* Start offset of contributing tile parts */
+ OPJ_OFF_T* m_intersecting_tile_parts_offset;
+
/** to tell that a tile can be decoded. */
OPJ_BITFIELD m_can_decode : 1;
OPJ_BITFIELD m_discard_tiles : 1;