Merge pull request #1163 from nforro/memory-and-resource-leaks
[openjpeg.git] / src / bin / jp2 / opj_decompress.c
index 397e637080d48e2683cd808afc62363d308a8051..a28a194bb7c738d23bc121d2d4c79d33fe021d91 100644 (file)
@@ -134,7 +134,7 @@ typedef struct opj_decompress_params {
     /** Verbose mode */
     OPJ_BOOL m_verbose;
 
-    /** tile number ot the decoded tile*/
+    /** tile number of the decoded tile */
     OPJ_UINT32 tile_index;
     /** Nb of tile to decode */
     OPJ_UINT32 nb_tile_to_decode;
@@ -150,6 +150,12 @@ typedef struct opj_decompress_params {
     int split_pnm;
     /** number of threads */
     int num_threads;
+    /* Quiet */
+    int quiet;
+    /** number of components to decode */
+    OPJ_UINT32 numcomps;
+    /** indices of components to decode */
+    OPJ_UINT32* comps_indices;
 } opj_decompress_parameters;
 
 /* -------------------------------------------------------------------------- */
@@ -225,6 +231,10 @@ static void decode_help_display(void)
             "    If 'C' is specified (default), values are clipped.\n"
             "    If 'S' is specified, values are scaled.\n"
             "    A 0 value can be specified (meaning original bit depth).\n");
+    fprintf(stdout, "  -c first_comp_index[,second_comp_index][,...]\n"
+            "    OPTIONAL\n"
+            "    To limit the number of components to decoded.\n"
+            "    Component indices are numbered starting at 0.\n");
     fprintf(stdout, "  -force-rgb\n"
             "    Force output image colorspace to RGB\n"
             "  -upsample\n"
@@ -232,9 +242,11 @@ static void decode_help_display(void)
             "  -split-pnm\n"
             "    Split output components to different files when writing to PNM\n");
     if (opj_has_thread_support()) {
-        fprintf(stdout, "  -threads <num_threads>\n"
-                "    Number of threads to use for decoding.\n");
+        fprintf(stdout, "  -threads <num_threads|ALL_CPUS>\n"
+                "    Number of threads to use for decoding or ALL_CPUS for all available cores.\n");
     }
+    fprintf(stdout, "  -quiet\n"
+            "    Disable output from the library and other output.\n");
     /* UniPG>> */
 #ifdef USE_JPWL
     fprintf(stdout, "  -W <options>\n"
@@ -552,10 +564,11 @@ int parse_cmdline_decoder(int argc, char **argv,
         {"force-rgb", NO_ARG,  NULL, 1},
         {"upsample",  NO_ARG,  NULL, 1},
         {"split-pnm", NO_ARG,  NULL, 1},
-        {"threads",   REQ_ARG, NULL, 'T'}
+        {"threads",   REQ_ARG, NULL, 'T'},
+        {"quiet", NO_ARG,  NULL, 1},
     };
 
-    const char optlist[] = "i:o:r:l:x:d:t:p:"
+    const char optlist[] = "i:o:r:l:x:d:t:p:c:"
 
                            /* UniPG>> */
 #ifdef USE_JPWL
@@ -567,6 +580,7 @@ int parse_cmdline_decoder(int argc, char **argv,
     long_option[2].flag = &(parameters->force_rgb);
     long_option[3].flag = &(parameters->upsample);
     long_option[4].flag = &(parameters->split_pnm);
+    long_option[6].flag = &(parameters->quiet);
     totlen = sizeof(long_option);
     opj_reset_options_reading();
     img_fol->set_out_format = 0;
@@ -764,6 +778,25 @@ int parse_cmdline_decoder(int argc, char **argv,
                 return 1;
             }
         }
+        break;
+
+        /* ----------------------------------------------------- */
+        case 'c': { /* Componenets */
+            const char* iter = opj_optarg;
+            while (1) {
+                parameters->numcomps ++;
+                parameters->comps_indices = (OPJ_UINT32*) realloc(
+                                                parameters->comps_indices,
+                                                parameters->numcomps * sizeof(OPJ_UINT32));
+                parameters->comps_indices[parameters->numcomps - 1] =
+                    (OPJ_UINT32) atoi(iter);
+                iter = strchr(iter, ',');
+                if (iter == NULL) {
+                    break;
+                }
+                iter ++;
+            }
+        }
         break;
             /* ----------------------------------------------------- */
 
@@ -830,8 +863,10 @@ int parse_cmdline_decoder(int argc, char **argv,
                 token = strtok(NULL, ",");
             };
             parameters->jpwl_correct = OPJ_TRUE;
-            fprintf(stdout, "JPWL correction capability activated\n");
-            fprintf(stdout, "- expecting %d components\n", parameters->jpwl_exp_comps);
+            if (!(parameter->quiet)) {
+                fprintf(stdout, "JPWL correction capability activated\n");
+                fprintf(stdout, "- expecting %d components\n", parameters->jpwl_exp_comps);
+            }
         }
         break;
 #endif /* USE_JPWL */
@@ -929,7 +964,8 @@ OPJ_FLOAT64 opj_clock(void)
     /* cout << "freq = " << ((double) freq.QuadPart) << endl; */
     /* t is the high resolution performance counter (see MSDN) */
     QueryPerformanceCounter(& t) ;
-    return freq.QuadPart ? (t.QuadPart / (OPJ_FLOAT64)freq.QuadPart) : 0;
+    return freq.QuadPart ? ((OPJ_FLOAT64)t.QuadPart / (OPJ_FLOAT64)freq.QuadPart) :
+           0;
 #elif defined(__linux)
     struct timespec ts;
     clock_gettime(CLOCK_REALTIME, &ts);
@@ -976,6 +1012,14 @@ static void info_callback(const char *msg, void *client_data)
     (void)client_data;
     fprintf(stdout, "[INFO] %s", msg);
 }
+/**
+sample quiet callback expecting no client object
+*/
+static void quiet_callback(const char *msg, void *client_data)
+{
+    (void)msg;
+    (void)client_data;
+}
 
 static void set_default_parameters(opj_decompress_parameters* parameters)
 {
@@ -998,6 +1042,9 @@ static void destroy_parameters(opj_decompress_parameters* parameters)
             free(parameters->precision);
             parameters->precision = NULL;
         }
+
+        free(parameters->comps_indices);
+        parameters->comps_indices = NULL;
     }
 }
 
@@ -1280,6 +1327,7 @@ int main(int argc, char **argv)
     int failed = 0;
     OPJ_FLOAT64 t, tCumulative = 0;
     OPJ_UINT32 numDecompressedImages = 0;
+    OPJ_UINT32 cp_reduce;
 
     /* set decoding parameters to default values */
     set_default_parameters(&parameters);
@@ -1293,6 +1341,15 @@ int main(int argc, char **argv)
         goto fin;
     }
 
+    cp_reduce = parameters.core.cp_reduce;
+    if (getenv("USE_OPJ_SET_DECODED_RESOLUTION_FACTOR") != NULL) {
+        /* For debugging/testing purposes, do not set the cp_reduce member */
+        /* if USE_OPJ_SET_DECODED_RESOLUTION_FACTOR is defined, but used */
+        /* the opj_set_decoded_resolution_factor() API instead */
+        parameters.core.cp_reduce = 0;
+    }
+
+
     /* Initialize reading of directory */
     if (img_fol.set_imgdir == 1) {
         int it_image;
@@ -1325,7 +1382,7 @@ int main(int argc, char **argv)
             goto fin;
         }
         if (num_images == 0) {
-            fprintf(stdout, "Folder is empty\n");
+            fprintf(stderr, "Folder is empty\n");
             failed = 1;
             goto fin;
         }
@@ -1336,7 +1393,9 @@ int main(int argc, char **argv)
     /*Decoding image one by one*/
     for (imageno = 0; imageno < num_images ; imageno++)  {
 
-        fprintf(stderr, "\n");
+        if (!parameters.quiet) {
+            fprintf(stderr, "\n");
+        }
 
         if (img_fol.set_imgdir == 1) {
             if (get_next_file(imageno, dirptr, &img_fol, &parameters)) {
@@ -1383,10 +1442,18 @@ int main(int argc, char **argv)
             continue;
         }
 
-        /* catch events using our callbacks and give a local context */
-        opj_set_info_handler(l_codec, info_callback, 00);
-        opj_set_warning_handler(l_codec, warning_callback, 00);
-        opj_set_error_handler(l_codec, error_callback, 00);
+        if (parameters.quiet) {
+            /* Set all callbacks to quiet */
+            opj_set_info_handler(l_codec, quiet_callback, 00);
+            opj_set_warning_handler(l_codec, quiet_callback, 00);
+            opj_set_error_handler(l_codec, quiet_callback, 00);
+        } else {
+            /* catch events using our callbacks and give a local context */
+            opj_set_info_handler(l_codec, info_callback, 00);
+            opj_set_warning_handler(l_codec, warning_callback, 00);
+            opj_set_error_handler(l_codec, error_callback, 00);
+        }
+
 
         t = opj_clock();
 
@@ -1418,11 +1485,50 @@ int main(int argc, char **argv)
             goto fin;
         }
 
+        if (parameters.numcomps) {
+            if (! opj_set_decoded_components(l_codec,
+                                             parameters.numcomps,
+                                             parameters.comps_indices,
+                                             OPJ_FALSE)) {
+                fprintf(stderr,
+                        "ERROR -> opj_decompress: failed to set the component indices!\n");
+                opj_destroy_codec(l_codec);
+                opj_stream_destroy(l_stream);
+                opj_image_destroy(image);
+                failed = 1;
+                goto fin;
+            }
+        }
+
+        if (getenv("USE_OPJ_SET_DECODED_RESOLUTION_FACTOR") != NULL) {
+            /* For debugging/testing purposes, and also an illustration on how to */
+            /* use the alternative API opj_set_decoded_resolution_factor() instead */
+            /* of setting parameters.cp_reduce */
+            if (! opj_set_decoded_resolution_factor(l_codec, cp_reduce)) {
+                fprintf(stderr,
+                        "ERROR -> opj_decompress: failed to set the resolution factor tile!\n");
+                opj_destroy_codec(l_codec);
+                opj_stream_destroy(l_stream);
+                opj_image_destroy(image);
+                failed = 1;
+                goto fin;
+            }
+        }
+
         if (!parameters.nb_tile_to_decode) {
+            if (getenv("SKIP_OPJ_SET_DECODE_AREA") != NULL &&
+                    parameters.DA_x0 == 0 &&
+                    parameters.DA_y0 == 0 &&
+                    parameters.DA_x1 == 0 &&
+                    parameters.DA_y1 == 0) {
+                /* For debugging/testing purposes, */
+                /* do nothing if SKIP_OPJ_SET_DECODE_AREA env variable */
+                /* is defined and no decoded area has been set */
+            }
             /* Optional if you want decode the entire image */
-            if (!opj_set_decode_area(l_codec, image, (OPJ_INT32)parameters.DA_x0,
-                                     (OPJ_INT32)parameters.DA_y0, (OPJ_INT32)parameters.DA_x1,
-                                     (OPJ_INT32)parameters.DA_y1)) {
+            else if (!opj_set_decode_area(l_codec, image, (OPJ_INT32)parameters.DA_x0,
+                                          (OPJ_INT32)parameters.DA_y0, (OPJ_INT32)parameters.DA_x1,
+                                          (OPJ_INT32)parameters.DA_y1)) {
                 fprintf(stderr, "ERROR -> opj_decompress: failed to set the decoded area\n");
                 opj_stream_destroy(l_stream);
                 opj_destroy_codec(l_codec);
@@ -1442,15 +1548,14 @@ int main(int argc, char **argv)
                 goto fin;
             }
         } else {
-
-            /* It is just here to illustrate how to use the resolution after set parameters */
-            /*if (!opj_set_decoded_resolution_factor(l_codec, 5)) {
-                fprintf(stderr, "ERROR -> opj_decompress: failed to set the resolution factor tile!\n");
-                opj_destroy_codec(l_codec);
-                opj_stream_destroy(l_stream);
-                opj_image_destroy(image);
-                failed = 1; goto fin;
-            }*/
+            if (!(parameters.DA_x0 == 0 &&
+                    parameters.DA_y0 == 0 &&
+                    parameters.DA_x1 == 0 &&
+                    parameters.DA_y1 == 0)) {
+                if (!(parameters.quiet)) {
+                    fprintf(stderr, "WARNING: -d option ignored when used together with -t\n");
+                }
+            }
 
             if (!opj_get_decoded_tile(l_codec, l_stream, image, parameters.tile_index)) {
                 fprintf(stderr, "ERROR -> opj_decompress: failed to decode tile!\n");
@@ -1460,7 +1565,20 @@ int main(int argc, char **argv)
                 failed = 1;
                 goto fin;
             }
-            fprintf(stdout, "tile %d is decoded!\n\n", parameters.tile_index);
+            if (!(parameters.quiet)) {
+                fprintf(stdout, "tile %d is decoded!\n\n", parameters.tile_index);
+            }
+        }
+
+        /* FIXME? Shouldn't that situation be considered as an error of */
+        /* opj_decode() / opj_get_decoded_tile() ? */
+        if (image->comps[0].data == NULL) {
+            fprintf(stderr, "ERROR -> opj_decompress: no image data!\n");
+            opj_destroy_codec(l_codec);
+            opj_stream_destroy(l_stream);
+            opj_image_destroy(image);
+            failed = 1;
+            goto fin;
         }
 
         tCumulative += opj_clock() - t;
@@ -1574,7 +1692,7 @@ int main(int argc, char **argv)
             if (imagetopnm(image, parameters.outfile, parameters.split_pnm)) {
                 fprintf(stderr, "[ERROR] Outfile %s not generated\n", parameters.outfile);
                 failed = 1;
-            } else {
+            } else if (!(parameters.quiet)) {
                 fprintf(stdout, "[INFO] Generated Outfile %s\n", parameters.outfile);
             }
             break;
@@ -1583,7 +1701,7 @@ int main(int argc, char **argv)
             if (imagetopgx(image, parameters.outfile)) {
                 fprintf(stderr, "[ERROR] Outfile %s not generated\n", parameters.outfile);
                 failed = 1;
-            } else {
+            } else if (!(parameters.quiet)) {
                 fprintf(stdout, "[INFO] Generated Outfile %s\n", parameters.outfile);
             }
             break;
@@ -1592,7 +1710,7 @@ int main(int argc, char **argv)
             if (imagetobmp(image, parameters.outfile)) {
                 fprintf(stderr, "[ERROR] Outfile %s not generated\n", parameters.outfile);
                 failed = 1;
-            } else {
+            } else if (!(parameters.quiet)) {
                 fprintf(stdout, "[INFO] Generated Outfile %s\n", parameters.outfile);
             }
             break;
@@ -1601,7 +1719,7 @@ int main(int argc, char **argv)
             if (imagetotif(image, parameters.outfile)) {
                 fprintf(stderr, "[ERROR] Outfile %s not generated\n", parameters.outfile);
                 failed = 1;
-            } else {
+            } else if (!(parameters.quiet)) {
                 fprintf(stdout, "[INFO] Generated Outfile %s\n", parameters.outfile);
             }
             break;
@@ -1611,7 +1729,7 @@ int main(int argc, char **argv)
                 fprintf(stderr, "[ERROR] Error generating raw file. Outfile %s not generated\n",
                         parameters.outfile);
                 failed = 1;
-            } else {
+            } else if (!(parameters.quiet)) {
                 fprintf(stdout, "[INFO] Generated Outfile %s\n", parameters.outfile);
             }
             break;
@@ -1622,7 +1740,7 @@ int main(int argc, char **argv)
                         "[ERROR] Error generating rawl file. Outfile %s not generated\n",
                         parameters.outfile);
                 failed = 1;
-            } else {
+            } else if (!(parameters.quiet)) {
                 fprintf(stdout, "[INFO] Generated Outfile %s\n", parameters.outfile);
             }
             break;
@@ -1632,7 +1750,7 @@ int main(int argc, char **argv)
                 fprintf(stderr, "[ERROR] Error generating tga file. Outfile %s not generated\n",
                         parameters.outfile);
                 failed = 1;
-            } else {
+            } else if (!(parameters.quiet)) {
                 fprintf(stdout, "[INFO] Generated Outfile %s\n", parameters.outfile);
             }
             break;
@@ -1642,7 +1760,7 @@ int main(int argc, char **argv)
                 fprintf(stderr, "[ERROR] Error generating png file. Outfile %s not generated\n",
                         parameters.outfile);
                 failed = 1;
-            } else {
+            } else if (!(parameters.quiet)) {
                 fprintf(stdout, "[INFO] Generated Outfile %s\n", parameters.outfile);
             }
             break;
@@ -1685,7 +1803,7 @@ fin:
         }
         free(dirptr);
     }
-    if (numDecompressedImages) {
+    if (numDecompressedImages && !failed && !(parameters.quiet)) {
         fprintf(stdout, "decode time: %d ms\n",
                 (int)((tCumulative * 1000.0) / (OPJ_FLOAT64)numDecompressedImages));
     }