Merge pull request #1253 from rouault/floating_point_irreversible_encoding
authorEven Rouault <even.rouault@spatialys.com>
Fri, 9 Oct 2020 11:25:27 +0000 (13:25 +0200)
committerGitHub <noreply@github.com>
Fri, 9 Oct 2020 11:25:27 +0000 (13:25 +0200)
Single-threaded performance improvements in forward DWT for 5-3 and 9-7 (and other improvements)

src/bin/jp2/opj_decompress.c
src/bin/jpip/CMakeLists.txt
src/lib/openjp2/j2k.c
src/lib/openjp2/jp2.c
src/lib/openjp2/t1.c
tests/nonregression/CMakeLists.txt
wrapping/java/openjp2/CMakeLists.txt

index 7eeb0952f672a0b86284ab0e767aa804ef2bcd52..2634907f015452607d9dd35f9835c6015090e3b8 100644 (file)
@@ -1316,10 +1316,6 @@ static opj_image_t* upsample_image_components(opj_image_t* original)
 int main(int argc, char **argv)
 {
     opj_decompress_parameters parameters;           /* decompression parameters */
-    opj_image_t* image = NULL;
-    opj_stream_t *l_stream = NULL;              /* Stream */
-    opj_codec_t* l_codec = NULL;                /* Handle to a decompressor */
-    opj_codestream_index_t* cstr_index = NULL;
 
     OPJ_INT32 num_images, imageno;
     img_fol_t img_fol;
@@ -1393,6 +1389,10 @@ int main(int argc, char **argv)
 
     /*Decoding image one by one*/
     for (imageno = 0; imageno < num_images ; imageno++)  {
+        opj_image_t* image = NULL;
+        opj_stream_t *l_stream = NULL;              /* Stream */
+        opj_codec_t* l_codec = NULL;                /* Handle to a decompressor */
+        opj_codestream_index_t* cstr_index = NULL;
 
         if (!parameters.quiet) {
             fprintf(stderr, "\n");
index 301d885bace0a74916080ffece561aa84ea429ed..8dbf577534f022b187180e3898027bbdbb7fc1a4 100644 (file)
@@ -57,14 +57,14 @@ add_executable(${exe} ${exe}.c)
 endforeach()
 
 # Build the two java clients:
-find_package(Java 1.5 COMPONENTS Development) # javac, jar
+find_package(Java 1.6 COMPONENTS Development) # javac, jar
 
 # User can override this:
 if(NOT DEFINED JAVA_SOURCE_VERSION)
-  set(JAVA_SOURCE_VERSION 1.5)
+  set(JAVA_SOURCE_VERSION 1.6)
 endif()
 if(NOT DEFINED JAVA_TARGET_VERSION)
-  set(JAVA_TARGET_VERSION 1.5)
+  set(JAVA_TARGET_VERSION 1.6)
 endif()
 
 # Only build the java viewer if dev is found:
index 1a6cdc3e905ff3e8ed8ee6f71a77d7eea7826a97..08e79598eedf20021edc064a41786a2df26744a0 100644 (file)
@@ -2707,6 +2707,12 @@ static OPJ_BOOL opj_j2k_read_cod(opj_j2k_t *p_j2k,
     opj_read_bytes(p_header_data, &l_tcp->mct, 1);          /* SGcod (C) */
     ++p_header_data;
 
+    if (l_tcp->mct > 1) {
+        opj_event_msg(p_manager, EVT_ERROR,
+                      "Invalid multiple component transformation\n");
+        return OPJ_FALSE;
+    }
+
     p_header_size -= 5;
     for (i = 0; i < l_image->numcomps; ++i) {
         l_tcp->tccps[i].csty = l_tcp->csty & J2K_CCP_CSTY_PRT;
@@ -5197,7 +5203,7 @@ static OPJ_BOOL opj_j2k_update_rates(opj_j2k_t *p_j2k,
     OPJ_FLOAT32 * l_rates = 0;
     OPJ_FLOAT32 l_sot_remove;
     OPJ_UINT32 l_bits_empty, l_size_pixel;
-    OPJ_UINT32 l_tile_size = 0;
+    OPJ_UINT64 l_tile_size = 0;
     OPJ_UINT32 l_last_res;
     OPJ_FLOAT32(* l_tp_stride_func)(opj_tcp_t *) = 00;
 
@@ -5241,25 +5247,12 @@ static OPJ_BOOL opj_j2k_update_rates(opj_j2k_t *p_j2k,
             l_rates = l_tcp->rates;
 
             /* Modification of the RATE >> */
-            if (*l_rates > 0.0f) {
-                *l_rates = (((OPJ_FLOAT32)(l_size_pixel * (OPJ_UINT32)(l_x1 - l_x0) *
-                                           (OPJ_UINT32)(l_y1 - l_y0)))
-                            /
-                            ((*l_rates) * (OPJ_FLOAT32)l_bits_empty)
-                           )
-                           -
-                           l_offset;
-            }
-
-            ++l_rates;
-
-            for (k = 1; k < l_tcp->numlayers; ++k) {
+            for (k = 0; k < l_tcp->numlayers; ++k) {
                 if (*l_rates > 0.0f) {
-                    *l_rates = (((OPJ_FLOAT32)(l_size_pixel * (OPJ_UINT32)(l_x1 - l_x0) *
-                                               (OPJ_UINT32)(l_y1 - l_y0)))
-                                /
-                                ((*l_rates) * (OPJ_FLOAT32)l_bits_empty)
-                               )
+                    *l_rates = (OPJ_FLOAT32)(((OPJ_FLOAT64)l_size_pixel * (OPJ_UINT32)(
+                                                  l_x1 - l_x0) *
+                                              (OPJ_UINT32)(l_y1 - l_y0))
+                                             / ((*l_rates) * (OPJ_FLOAT32)l_bits_empty))
                                -
                                l_offset;
                 }
@@ -5319,12 +5312,11 @@ static OPJ_BOOL opj_j2k_update_rates(opj_j2k_t *p_j2k,
     l_tile_size = 0;
 
     for (i = 0; i < l_image->numcomps; ++i) {
-        l_tile_size += (opj_uint_ceildiv(l_cp->tdx, l_img_comp->dx)
-                        *
-                        opj_uint_ceildiv(l_cp->tdy, l_img_comp->dy)
-                        *
-                        l_img_comp->prec
-                       );
+        l_tile_size += (OPJ_UINT64)opj_uint_ceildiv(l_cp->tdx, l_img_comp->dx)
+                       *
+                       opj_uint_ceildiv(l_cp->tdy, l_img_comp->dy)
+                       *
+                       l_img_comp->prec;
 
         ++l_img_comp;
     }
@@ -5335,7 +5327,7 @@ static OPJ_BOOL opj_j2k_update_rates(opj_j2k_t *p_j2k,
     /* bin/test_tile_encoder 1 256 256 32 32 8 0 reversible_with_precinct.j2k 4 4 3 0 0 1 16 16 */
     /* TODO revise this to take into account the overhead linked to the */
     /* number of packets and number of code blocks in packets */
-    l_tile_size = (OPJ_UINT32)(l_tile_size * 1.4 / 8);
+    l_tile_size = (OPJ_UINT64)((double)l_tile_size * 1.4 / 8);
 
     /* Arbitrary amount to make the following work: */
     /* bin/test_tile_encoder 1 256 256 17 16 8 0 reversible_no_precinct.j2k 4 4 3 0 0 1 */
@@ -5343,10 +5335,17 @@ static OPJ_BOOL opj_j2k_update_rates(opj_j2k_t *p_j2k,
 
     l_tile_size += opj_j2k_get_specific_header_sizes(p_j2k);
 
-    p_j2k->m_specific_param.m_encoder.m_encoded_tile_size = l_tile_size;
+    if (l_tile_size > UINT_MAX) {
+        l_tile_size = UINT_MAX;
+    }
+
+    p_j2k->m_specific_param.m_encoder.m_encoded_tile_size = (OPJ_UINT32)l_tile_size;
     p_j2k->m_specific_param.m_encoder.m_encoded_tile_data =
         (OPJ_BYTE *) opj_malloc(p_j2k->m_specific_param.m_encoder.m_encoded_tile_size);
     if (p_j2k->m_specific_param.m_encoder.m_encoded_tile_data == 00) {
+        opj_event_msg(p_manager, EVT_ERROR,
+                      "Not enough memory to allocate m_encoded_tile_data. %u MB required\n",
+                      (OPJ_UINT32)(l_tile_size / 1024 / 1024));
         return OPJ_FALSE;
     }
 
@@ -8295,6 +8294,8 @@ OPJ_BOOL opj_j2k_read_header(opj_stream_private_t *p_stream,
 
     /*Allocate and initialize some elements of codestrem index*/
     if (!opj_j2k_allocate_tile_element_cstr_index(p_j2k)) {
+        opj_image_destroy(*p_image);
+        *p_image = NULL;
         return OPJ_FALSE;
     }
 
@@ -10515,9 +10516,9 @@ static OPJ_BOOL opj_j2k_read_SPCod_SPCoc(opj_j2k_t *p_j2k,
         return OPJ_FALSE;
     }
 
-    opj_read_bytes(l_current_ptr, &l_tccp->numresolutions,
-                   1);              /* SPcox (D) */
-    ++l_tccp->numresolutions;                                                                               /* tccp->numresolutions = read() + 1 */
+    /* SPcod (D) / SPcoc (A) */
+    opj_read_bytes(l_current_ptr, &l_tccp->numresolutions, 1);
+    ++l_tccp->numresolutions;  /* tccp->numresolutions = read() + 1 */
     if (l_tccp->numresolutions > OPJ_J2K_MAXRLVLS) {
         opj_event_msg(p_manager, EVT_ERROR,
                       "Invalid value for numresolutions : %d, max value is set in openjpeg.h at %d\n",
@@ -10538,11 +10539,13 @@ static OPJ_BOOL opj_j2k_read_SPCod_SPCoc(opj_j2k_t *p_j2k,
         return OPJ_FALSE;
     }
 
-    opj_read_bytes(l_current_ptr, &l_tccp->cblkw, 1);               /* SPcoc (E) */
+    /* SPcod (E) / SPcoc (B) */
+    opj_read_bytes(l_current_ptr, &l_tccp->cblkw, 1);
     ++l_current_ptr;
     l_tccp->cblkw += 2;
 
-    opj_read_bytes(l_current_ptr, &l_tccp->cblkh, 1);               /* SPcoc (F) */
+    /* SPcod (F) / SPcoc (C) */
+    opj_read_bytes(l_current_ptr, &l_tccp->cblkh, 1);
     ++l_current_ptr;
     l_tccp->cblkh += 2;
 
@@ -10553,8 +10556,8 @@ static OPJ_BOOL opj_j2k_read_SPCod_SPCoc(opj_j2k_t *p_j2k,
         return OPJ_FALSE;
     }
 
-
-    opj_read_bytes(l_current_ptr, &l_tccp->cblksty, 1);             /* SPcoc (G) */
+    /* SPcod (G) / SPcoc (D) */
+    opj_read_bytes(l_current_ptr, &l_tccp->cblksty, 1);
     ++l_current_ptr;
     if (l_tccp->cblksty & 0xC0U) { /* 2 msb are reserved, assume we can't read */
         opj_event_msg(p_manager, EVT_ERROR,
@@ -10562,9 +10565,16 @@ static OPJ_BOOL opj_j2k_read_SPCod_SPCoc(opj_j2k_t *p_j2k,
         return OPJ_FALSE;
     }
 
-    opj_read_bytes(l_current_ptr, &l_tccp->qmfbid, 1);              /* SPcoc (H) */
+    /* SPcod (H) / SPcoc (E) */
+    opj_read_bytes(l_current_ptr, &l_tccp->qmfbid, 1);
     ++l_current_ptr;
 
+    if (l_tccp->qmfbid > 1) {
+        opj_event_msg(p_manager, EVT_ERROR,
+                      "Error reading SPCod SPCoc element, Invalid transformation found\n");
+        return OPJ_FALSE;
+    }
+
     *p_header_size = *p_header_size - 5;
 
     /* use custom precinct size ? */
@@ -10574,8 +10584,9 @@ static OPJ_BOOL opj_j2k_read_SPCod_SPCoc(opj_j2k_t *p_j2k,
             return OPJ_FALSE;
         }
 
+        /* SPcod (I_i) / SPcoc (F_i) */
         for (i = 0; i < l_tccp->numresolutions; ++i) {
-            opj_read_bytes(l_current_ptr, &l_tmp, 1);               /* SPcoc (I_i) */
+            opj_read_bytes(l_current_ptr, &l_tmp, 1);
             ++l_current_ptr;
             /* Precinct exponent 0 is only allowed for lowest resolution level (Table A.21) */
             if ((i != 0) && (((l_tmp & 0xf) == 0) || ((l_tmp >> 4) == 0))) {
index 4809e3488c12a574afea6f25c6f4a8fdec9febe5..7c065ba742be2bbe60eaa958e5583b1f7fead8d6 100644 (file)
@@ -586,6 +586,12 @@ static OPJ_BOOL opj_jp2_read_ihdr(opj_jp2_t *jp2,
     opj_read_bytes(p_image_header_data, &(jp2->numcomps), 2);   /* NC */
     p_image_header_data += 2;
 
+    if (jp2->h < 1 || jp2->w < 1 || jp2->numcomps < 1) {
+        opj_event_msg(p_manager, EVT_ERROR,
+                      "Wrong values for: w(%d) h(%d) numcomps(%d) (ihdr)\n",
+                      jp2->w, jp2->h, jp2->numcomps);
+        return OPJ_FALSE;
+    }
     if ((jp2->numcomps - 1U) >=
             16384U) { /* unsigned underflow is well defined: 1U <= jp2->numcomps <= 16384U */
         opj_event_msg(p_manager, EVT_ERROR, "Invalid number of components (ihdr)\n");
index 92030b217160125b3f86a038aff7f2399c51c61e..a850f4ff86163146af73368c3f9727a789b1537f 100644 (file)
@@ -1647,7 +1647,21 @@ static void opj_t1_clbl_decode_processor(void* user_data, opj_tls_t* tls)
     t1 = (opj_t1_t*) opj_tls_get(tls, OPJ_TLS_KEY_T1);
     if (t1 == NULL) {
         t1 = opj_t1_create(OPJ_FALSE);
-        opj_tls_set(tls, OPJ_TLS_KEY_T1, t1, opj_t1_destroy_wrapper);
+        if (t1 == NULL) {
+            opj_event_msg(job->p_manager, EVT_ERROR,
+                          "Cannot allocate Tier 1 handle\n");
+            *(job->pret) = OPJ_FALSE;
+            opj_free(job);
+            return;
+        }
+        if (!opj_tls_set(tls, OPJ_TLS_KEY_T1, t1, opj_t1_destroy_wrapper)) {
+            opj_event_msg(job->p_manager, EVT_ERROR,
+                          "Unable to set t1 handle as TLS\n");
+            opj_t1_destroy(t1);
+            *(job->pret) = OPJ_FALSE;
+            opj_free(job);
+            return;
+        }
     }
     t1->mustuse_cblkdatabuffer = job->mustuse_cblkdatabuffer;
 
index f1813ed8e5d8013d3632d26d27c1f1996a427911..7cbe01e050ff82c514b0dc9d5248498c9c8f065e 100644 (file)
@@ -34,7 +34,6 @@ set(BLACKLIST_JPEG2000_TMP
     edf_c2_1178956.jp2
     edf_c2_1000290.jp2
     #edf_c2_1000691.jp2 # ok
-    #edf_c2_20.jp2 #looks ok as per kdu_jp2info
     edf_c2_1377017.jp2
     edf_c2_1002767.jp2
     edf_c2_10025.jp2
@@ -61,6 +60,7 @@ set(BLACKLIST_JPEG2000
     broken2.jp2
     broken3.jp2
     broken4.jp2
+    edf_c2_20.jp2 #may look ok as per kdu_jp2info, but inspection it reveals that the transformation value is out of range
     gdal_fuzzer_assert_in_opj_j2k_read_SQcd_SQcc.patch.jp2     
     gdal_fuzzer_check_comp_dx_dy.jp2
     gdal_fuzzer_check_number_of_tiles.jp2
@@ -82,6 +82,8 @@ set(BLACKLIST_JPEG2000
     issue475.jp2 #kdu_jp2info ok
     issue413.jp2 #kdu_jp2info ok
     issue823.jp2 #kdu_jp2info ok
+    issue826.jp2 #inspection reveales that the transformation value is out of range
+    oss-fuzz2785.jp2 #inspection reveales that the transformation value is out of range
    )
 
 file(GLOB_RECURSE OPJ_DATA_NR_LIST
index eb3da0edbc69cb84e44fdf1b12ebaad781a163e3..e4639385f09600c9455d49bb5a92ca86dd436efa 100644 (file)
@@ -44,7 +44,7 @@ install(TARGETS openjpegjni
 )
 
 # build jar:
-find_package(Java 1.5 REQUIRED) # javac, jar
+find_package(Java 1.6 REQUIRED) # javac, jar
 
 # build dep list:
 file(GLOB java_srcs "java-sources/org/openJpeg/*.java")