Merge branch 'pr1107'
[openjpeg.git] / src / lib / openjp2 / j2k.c
index 8bac309faacb5aaa419bc93ebc840c6af2bea08a..4169cd672b78eae5a7ea9222b0288820ccbd9772 100644 (file)
@@ -508,7 +508,7 @@ static OPJ_BOOL opj_j2k_write_cod(opj_j2k_t *p_j2k,
                                   opj_event_mgr_t * p_manager);
 
 /**
- * Reads a COD marker (Coding Styke defaults)
+ * Reads a COD marker (Coding style defaults)
  * @param       p_header_data   the data contained in the COD box.
  * @param       p_j2k                   the jpeg2000 codec.
  * @param       p_header_size   the size of the data contained in the COD marker.
@@ -1925,7 +1925,8 @@ static OPJ_BOOL opj_j2k_read_soc(opj_j2k_t *p_j2k,
     /* FIXME move it in a index structure included in p_j2k*/
     p_j2k->cstr_index->main_head_start = opj_stream_tell(p_stream) - 2;
 
-    opj_event_msg(p_manager, EVT_INFO, "Start to read j2k main header (%d).\n",
+    opj_event_msg(p_manager, EVT_INFO,
+                  "Start to read j2k main header (%" PRId64 ").\n",
                   p_j2k->cstr_index->main_head_start);
 
     /* Add the marker to the codestream index*/
@@ -2625,7 +2626,7 @@ static OPJ_BOOL opj_j2k_write_cod(opj_j2k_t *p_j2k,
 }
 
 /**
- * Reads a COD marker (Coding Styke defaults)
+ * Reads a COD marker (Coding style defaults)
  * @param       p_header_data   the data contained in the COD box.
  * @param       p_j2k                   the jpeg2000 codec.
  * @param       p_header_size   the size of the data contained in the COD marker.
@@ -2657,12 +2658,17 @@ static OPJ_BOOL opj_j2k_read_cod(opj_j2k_t *p_j2k,
             &l_cp->tcps[p_j2k->m_current_tile_number] :
             p_j2k->m_specific_param.m_decoder.m_default_tcp;
 
+#if 0
+    /* This check was added per https://github.com/uclouvain/openjpeg/commit/daed8cc9195555e101ab708a501af2dfe6d5e001 */
+    /* but this is no longer necessary to handle issue476.jp2 */
+    /* and this actually cause issues on legit files. See https://github.com/uclouvain/openjpeg/issues/1043 */
     /* Only one COD per tile */
     if (l_tcp->cod) {
         opj_event_msg(p_manager, EVT_ERROR,
                       "COD marker already read. No more than one COD marker per tile.\n");
         return OPJ_FALSE;
     }
+#endif
     l_tcp->cod = 1;
 
     /* Make sure room is sufficient */
@@ -3502,11 +3508,10 @@ static OPJ_BOOL opj_j2k_read_poc(opj_j2k_t *p_j2k,
     l_old_poc_nb = l_tcp->POC ? l_tcp->numpocs + 1 : 0;
     l_current_poc_nb += l_old_poc_nb;
 
-    if (l_current_poc_nb >= 32) {
+    if (l_current_poc_nb >= J2K_MAX_POCS) {
         opj_event_msg(p_manager, EVT_ERROR, "Too many POCs %d\n", l_current_poc_nb);
         return OPJ_FALSE;
     }
-    assert(l_current_poc_nb < 32);
 
     /* now poc is in use.*/
     l_tcp->POC = 1;
@@ -4090,7 +4095,12 @@ static OPJ_BOOL opj_j2k_merge_ppt(opj_tcp_t *p_tcp, opj_event_mgr_t * p_manager)
     /* preconditions */
     assert(p_tcp != 00);
     assert(p_manager != 00);
-    assert(p_tcp->ppt_buffer == NULL);
+
+    if (p_tcp->ppt_buffer != NULL) {
+        opj_event_msg(p_manager, EVT_ERROR,
+                      "opj_j2k_merge_ppt() has already been called\n");
+        return OPJ_FALSE;
+    }
 
     if (p_tcp->ppt == 0U) {
         return OPJ_TRUE;
@@ -4669,9 +4679,11 @@ static OPJ_BOOL opj_j2k_write_sod(opj_j2k_t *p_j2k,
 
     if (p_j2k->m_specific_param.m_encoder.m_current_tile_part_number == 0) {
         p_tile_coder->tcd_image->tiles->packno = 0;
+#ifdef deadcode
         if (l_cstr_info) {
             l_cstr_info->packno = 0;
         }
+#endif
     }
 
     *p_data_written = 0;
@@ -6418,7 +6430,9 @@ void opj_j2k_setup_decoder(opj_j2k_t *j2k, opj_dparameters_t *parameters)
 
 OPJ_BOOL opj_j2k_set_threads(opj_j2k_t *j2k, OPJ_UINT32 num_threads)
 {
-    if (opj_has_thread_support()) {
+    /* Currently we pass the thread-pool to the tcd, so we cannot re-set it */
+    /* afterwards */
+    if (opj_has_thread_support() && j2k->m_tcd == NULL) {
         opj_thread_pool_destroy(j2k->m_tp);
         j2k->m_tp = NULL;
         if (num_threads <= (OPJ_UINT32)INT_MAX) {
@@ -6435,14 +6449,27 @@ OPJ_BOOL opj_j2k_set_threads(opj_j2k_t *j2k, OPJ_UINT32 num_threads)
 
 static int opj_j2k_get_default_thread_count()
 {
-    const char* num_threads = getenv("OPJ_NUM_THREADS");
-    if (num_threads == NULL || !opj_has_thread_support()) {
+    const char* num_threads_str = getenv("OPJ_NUM_THREADS");
+    int num_cpus;
+    int num_threads;
+
+    if (num_threads_str == NULL || !opj_has_thread_support()) {
         return 0;
     }
-    if (strcmp(num_threads, "ALL_CPUS") == 0) {
-        return opj_get_num_cpus();
+    num_cpus = opj_get_num_cpus();
+    if (strcmp(num_threads_str, "ALL_CPUS") == 0) {
+        return num_cpus;
+    }
+    if (num_cpus == 0) {
+        num_cpus = 32;
     }
-    return atoi(num_threads);
+    num_threads = atoi(num_threads_str);
+    if (num_threads < 0) {
+        num_threads = 0;
+    } else if (num_threads > 2 * num_cpus) {
+        num_threads = 2 * num_cpus;
+    }
+    return num_threads;
 }
 
 /* ----------------------------------------------------------------------- */
@@ -8266,6 +8293,11 @@ void opj_j2k_destroy(opj_j2k_t *p_j2k)
             p_j2k->m_specific_param.m_decoder.m_header_data = 00;
             p_j2k->m_specific_param.m_decoder.m_header_data_size = 0;
         }
+
+        opj_free(p_j2k->m_specific_param.m_decoder.m_comps_indices_to_decode);
+        p_j2k->m_specific_param.m_decoder.m_comps_indices_to_decode = 00;
+        p_j2k->m_specific_param.m_decoder.m_numcomps_to_decode = 0;
+
     } else {
 
         if (p_j2k->m_specific_param.m_encoder.m_encoded_tile_data) {
@@ -8551,7 +8583,7 @@ static OPJ_BOOL opj_j2k_need_nb_tile_parts_correction(opj_stream_private_t
             break;
         }
 
-        if ((l_tot_len == 0U) || (l_tot_len < 14U)) {
+        if (l_tot_len < 14U) {
             /* last SOT until EOC or invalid Psot value */
             /* assume all is OK */
             if (! opj_stream_seek(p_stream, l_stream_pos_backup, p_manager)) {
@@ -8819,7 +8851,10 @@ OPJ_BOOL opj_j2k_read_tile_header(opj_j2k_t * p_j2k,
 
     /* Current marker is the EOC marker ?*/
     if (l_current_marker == J2K_MS_EOC) {
-        p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_EOC;
+        if (p_j2k->m_specific_param.m_decoder.m_state != J2K_STATE_EOC) {
+            p_j2k->m_current_tile_number = 0;
+            p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_EOC;
+        }
     }
 
     /* FIXME DOC ???*/
@@ -8914,6 +8949,8 @@ OPJ_BOOL opj_j2k_decode_tile(opj_j2k_t * p_j2k,
                               l_image_for_bounds->y0,
                               l_image_for_bounds->x1,
                               l_image_for_bounds->y1,
+                              p_j2k->m_specific_param.m_decoder.m_numcomps_to_decode,
+                              p_j2k->m_specific_param.m_decoder.m_comps_indices_to_decode,
                               l_tcp->m_data,
                               l_tcp->m_data_size,
                               p_tile_index,
@@ -9028,6 +9065,11 @@ static OPJ_BOOL opj_j2k_update_image_data(opj_tcd_t * p_tcd,
             p_src_data = l_tilec->data_win;
         }
 
+        if (p_src_data == NULL) {
+            /* Happens for partial component decoding */
+            continue;
+        }
+
         l_width_src = (OPJ_UINT32)(res_x1 - res_x0);
         l_height_src = (OPJ_UINT32)(res_y1 - res_y0);
 
@@ -9129,6 +9171,7 @@ static OPJ_BOOL opj_j2k_update_image_data(opj_tcd_t * p_tcd,
         /* Allocate output component buffer if necessary */
         if (l_img_comp_dest->data == NULL &&
                 l_start_offset_src == 0 && l_start_offset_dest == 0 &&
+                src_data_stride == l_img_comp_dest->w &&
                 l_width_dest == l_img_comp_dest->w &&
                 l_height_dest == l_img_comp_dest->h) {
             /* If the final image matches the tile buffer, then borrow it */
@@ -9227,6 +9270,65 @@ static OPJ_BOOL opj_j2k_update_image_dimensions(opj_image_t* p_image,
     return OPJ_TRUE;
 }
 
+OPJ_BOOL opj_j2k_set_decoded_components(opj_j2k_t *p_j2k,
+                                        OPJ_UINT32 numcomps,
+                                        const OPJ_UINT32* comps_indices,
+                                        opj_event_mgr_t * p_manager)
+{
+    OPJ_UINT32 i;
+    OPJ_BOOL* already_mapped;
+
+    if (p_j2k->m_private_image == NULL) {
+        opj_event_msg(p_manager, EVT_ERROR,
+                      "opj_read_header() should be called before "
+                      "opj_set_decoded_components().\n");
+        return OPJ_FALSE;
+    }
+
+    already_mapped = (OPJ_BOOL*) opj_calloc(sizeof(OPJ_BOOL),
+                                            p_j2k->m_private_image->numcomps);
+    if (already_mapped == NULL) {
+        return OPJ_FALSE;
+    }
+
+    for (i = 0; i < numcomps; i++) {
+        if (comps_indices[i] >= p_j2k->m_private_image->numcomps) {
+            opj_event_msg(p_manager, EVT_ERROR,
+                          "Invalid component index: %u\n",
+                          comps_indices[i]);
+            opj_free(already_mapped);
+            return OPJ_FALSE;
+        }
+        if (already_mapped[comps_indices[i]]) {
+            opj_event_msg(p_manager, EVT_ERROR,
+                          "Component index %u used several times\n",
+                          comps_indices[i]);
+            opj_free(already_mapped);
+            return OPJ_FALSE;
+        }
+        already_mapped[comps_indices[i]] = OPJ_TRUE;
+    }
+    opj_free(already_mapped);
+
+    opj_free(p_j2k->m_specific_param.m_decoder.m_comps_indices_to_decode);
+    if (numcomps) {
+        p_j2k->m_specific_param.m_decoder.m_comps_indices_to_decode =
+            (OPJ_UINT32*) opj_malloc(numcomps * sizeof(OPJ_UINT32));
+        if (p_j2k->m_specific_param.m_decoder.m_comps_indices_to_decode == NULL) {
+            p_j2k->m_specific_param.m_decoder.m_numcomps_to_decode = 0;
+            return OPJ_FALSE;
+        }
+        memcpy(p_j2k->m_specific_param.m_decoder.m_comps_indices_to_decode,
+               comps_indices,
+               numcomps * sizeof(OPJ_UINT32));
+    } else {
+        p_j2k->m_specific_param.m_decoder.m_comps_indices_to_decode = NULL;
+    }
+    p_j2k->m_specific_param.m_decoder.m_numcomps_to_decode = numcomps;
+
+    return OPJ_TRUE;
+}
+
 
 OPJ_BOOL opj_j2k_set_decode_area(opj_j2k_t *p_j2k,
                                  opj_image_t* p_image,
@@ -9240,7 +9342,7 @@ OPJ_BOOL opj_j2k_set_decode_area(opj_j2k_t *p_j2k,
     OPJ_UINT32 it_comp;
 
     if (p_j2k->m_cp.tw == 1 && p_j2k->m_cp.th == 1 &&
-            &p_j2k->m_cp.tcps[0].m_data != NULL) {
+            p_j2k->m_cp.tcps[0].m_data != NULL) {
         /* In the case of a single-tiled image whose codestream we have already */
         /* ingested, go on */
     }
@@ -9301,7 +9403,7 @@ OPJ_BOOL opj_j2k_set_decode_area(opj_j2k_t *p_j2k,
     }
 
     /* Up */
-    if (p_start_x < 0) {
+    if (p_start_y < 0) {
         opj_event_msg(p_manager, EVT_ERROR,
                       "Up position of the decoded area (region_y0=%d) should be >= 0.\n",
                       p_start_y);
@@ -10816,13 +10918,71 @@ static OPJ_BOOL opj_j2k_setup_decoding_tile(opj_j2k_t *p_j2k,
     return OPJ_TRUE;
 }
 
+static OPJ_BOOL opj_j2k_move_data_from_codec_to_output_image(opj_j2k_t * p_j2k,
+        opj_image_t * p_image)
+{
+    OPJ_UINT32 compno;
+
+    /* Move data and copy one information from codec to output image*/
+    if (p_j2k->m_specific_param.m_decoder.m_numcomps_to_decode > 0) {
+        opj_image_comp_t* newcomps =
+            (opj_image_comp_t*) opj_malloc(
+                p_j2k->m_specific_param.m_decoder.m_numcomps_to_decode *
+                sizeof(opj_image_comp_t));
+        if (newcomps == NULL) {
+            opj_image_destroy(p_j2k->m_private_image);
+            p_j2k->m_private_image = NULL;
+            return OPJ_FALSE;
+        }
+        for (compno = 0; compno < p_image->numcomps; compno++) {
+            opj_image_data_free(p_image->comps[compno].data);
+            p_image->comps[compno].data = NULL;
+        }
+        for (compno = 0;
+                compno < p_j2k->m_specific_param.m_decoder.m_numcomps_to_decode; compno++) {
+            OPJ_UINT32 src_compno =
+                p_j2k->m_specific_param.m_decoder.m_comps_indices_to_decode[compno];
+            memcpy(&(newcomps[compno]),
+                   &(p_j2k->m_output_image->comps[src_compno]),
+                   sizeof(opj_image_comp_t));
+            newcomps[compno].resno_decoded =
+                p_j2k->m_output_image->comps[src_compno].resno_decoded;
+            newcomps[compno].data = p_j2k->m_output_image->comps[src_compno].data;
+            p_j2k->m_output_image->comps[src_compno].data = NULL;
+        }
+        for (compno = 0; compno < p_image->numcomps; compno++) {
+            assert(p_j2k->m_output_image->comps[compno].data == NULL);
+            opj_image_data_free(p_j2k->m_output_image->comps[compno].data);
+            p_j2k->m_output_image->comps[compno].data = NULL;
+        }
+        p_image->numcomps = p_j2k->m_specific_param.m_decoder.m_numcomps_to_decode;
+        opj_free(p_image->comps);
+        p_image->comps = newcomps;
+    } else {
+        for (compno = 0; compno < p_image->numcomps; compno++) {
+            p_image->comps[compno].resno_decoded =
+                p_j2k->m_output_image->comps[compno].resno_decoded;
+            opj_image_data_free(p_image->comps[compno].data);
+            p_image->comps[compno].data = p_j2k->m_output_image->comps[compno].data;
+#if 0
+            char fn[256];
+            sprintf(fn, "/tmp/%d.raw", compno);
+            FILE *debug = fopen(fn, "wb");
+            fwrite(p_image->comps[compno].data, sizeof(OPJ_INT32),
+                   p_image->comps[compno].w * p_image->comps[compno].h, debug);
+            fclose(debug);
+#endif
+            p_j2k->m_output_image->comps[compno].data = NULL;
+        }
+    }
+    return OPJ_TRUE;
+}
+
 OPJ_BOOL opj_j2k_decode(opj_j2k_t * p_j2k,
                         opj_stream_private_t * p_stream,
                         opj_image_t * p_image,
                         opj_event_mgr_t * p_manager)
 {
-    OPJ_UINT32 compno;
-
     if (!p_image) {
         return OPJ_FALSE;
     }
@@ -10873,23 +11033,7 @@ OPJ_BOOL opj_j2k_decode(opj_j2k_t * p_j2k,
     }
 
     /* Move data and copy one information from codec to output image*/
-    for (compno = 0; compno < p_image->numcomps; compno++) {
-        p_image->comps[compno].resno_decoded =
-            p_j2k->m_output_image->comps[compno].resno_decoded;
-        opj_image_data_free(p_image->comps[compno].data);
-        p_image->comps[compno].data = p_j2k->m_output_image->comps[compno].data;
-#if 0
-        char fn[256];
-        sprintf(fn, "/tmp/%d.raw", compno);
-        FILE *debug = fopen(fn, "wb");
-        fwrite(p_image->comps[compno].data, sizeof(OPJ_INT32),
-               p_image->comps[compno].w * p_image->comps[compno].h, debug);
-        fclose(debug);
-#endif
-        p_j2k->m_output_image->comps[compno].data = NULL;
-    }
-
-    return OPJ_TRUE;
+    return opj_j2k_move_data_from_codec_to_output_image(p_j2k, p_image);
 }
 
 OPJ_BOOL opj_j2k_get_tile(opj_j2k_t *p_j2k,
@@ -11004,20 +11148,7 @@ OPJ_BOOL opj_j2k_get_tile(opj_j2k_t *p_j2k,
     }
 
     /* Move data and copy one information from codec to output image*/
-    for (compno = 0; compno < p_image->numcomps; compno++) {
-        p_image->comps[compno].resno_decoded =
-            p_j2k->m_output_image->comps[compno].resno_decoded;
-
-        if (p_image->comps[compno].data) {
-            opj_image_data_free(p_image->comps[compno].data);
-        }
-
-        p_image->comps[compno].data = p_j2k->m_output_image->comps[compno].data;
-
-        p_j2k->m_output_image->comps[compno].data = NULL;
-    }
-
-    return OPJ_TRUE;
+    return opj_j2k_move_data_from_codec_to_output_image(p_j2k, p_image);
 }
 
 OPJ_BOOL opj_j2k_set_decoded_resolution_factor(opj_j2k_t *p_j2k,
@@ -11123,6 +11254,12 @@ OPJ_BOOL opj_j2k_encode(opj_j2k_t * p_j2k,
                 l_current_data = l_new_current_data;
                 l_max_tile_size = l_current_tile_size;
             }
+            if (l_current_data == NULL) {
+                /* Should not happen in practice, but will avoid Coverity to */
+                /* complain about a null pointer dereference */
+                assert(0);
+                return OPJ_FALSE;
+            }
 
             /* copy image data (32 bit) to l_current_data as contiguous, all-component, zero offset buffer */
             /* 32 bit components @ 8 bit precision get converted to 8 bit */