libjxl

FORK: libjxl patches used on blog
git clone https://git.neptards.moe/blog/libjxl.git
Log | Files | Refs | Submodules | README | LICENSE

benchmark_args.cc (10772B)


      1 // Copyright (c) the JPEG XL Project Authors. All rights reserved.
      2 //
      3 // Use of this source code is governed by a BSD-style
      4 // license that can be found in the LICENSE file.
      5 
      6 #include "tools/benchmark/benchmark_args.h"
      7 
      8 #include <stddef.h>
      9 #include <stdlib.h>
     10 
     11 #include <algorithm>
     12 #include <string>
     13 #include <vector>
     14 
     15 #include "lib/extras/codec.h"
     16 #include "lib/extras/dec/color_description.h"
     17 #include "lib/jxl/base/status.h"
     18 #include "lib/jxl/color_encoding_internal.h"
     19 #include "tools/benchmark/benchmark_codec_custom.h"  // for AddCommand..
     20 #include "tools/benchmark/benchmark_codec_jpeg.h"    // for AddCommand..
     21 #include "tools/benchmark/benchmark_codec_jxl.h"
     22 
     23 #ifdef BENCHMARK_PNG
     24 #include "tools/benchmark/benchmark_codec_png.h"
     25 #endif  // BENCHMARK_PNG
     26 
     27 #ifdef BENCHMARK_WEBP
     28 #include "tools/benchmark/benchmark_codec_webp.h"
     29 #endif  // BENCHMARK_WEBP
     30 
     31 #ifdef BENCHMARK_AVIF
     32 #include "tools/benchmark/benchmark_codec_avif.h"
     33 #endif  // BENCHMARK_AVIF
     34 
     35 namespace jpegxl {
     36 namespace tools {
     37 
     38 std::vector<std::string> SplitString(const std::string& s, char c) {
     39   std::vector<std::string> result;
     40   size_t pos = 0;
     41   for (size_t i = 0; i <= s.size(); i++) {
     42     if (i == s.size() || s[i] == c) {
     43       result.push_back(s.substr(pos, i - pos));
     44       pos = i + 1;
     45     }
     46   }
     47   return result;
     48 }
     49 
     50 int ParseIntParam(const std::string& param, int lower_bound, int upper_bound) {
     51   int val = strtol(param.substr(1).c_str(), nullptr, 10);
     52   JXL_CHECK(val >= lower_bound && val <= upper_bound);
     53   return val;
     54 }
     55 
     56 BenchmarkArgs* Args() {
     57   static BenchmarkArgs args;
     58   return &args;
     59 }
     60 
     61 Status BenchmarkArgs::AddCommandLineOptions() {
     62   AddString(&input, "input", "File or file pattern matching input files.");
     63   AddString(&codec, "codec",
     64             "Comma separated list of image codec descriptions to benchmark.",
     65             "jxl");
     66   AddFlag(&print_details, "print_details",
     67           "Prints size and distortion for each image. Not safe for "
     68           "concurrent benchmark runs.",
     69           false);
     70   AddFlag(&print_details_csv, "print_details_csv",
     71           "When print_details is used, print as CSV.", false);
     72   AddString(&extra_metrics, "extra_metrics",
     73             "Extra metrics to be computed. Only displayed with --print_details "
     74             "or --print_details_csv. Comma-separated list of NAME:COMMAND "
     75             "pairs; COMMAND is invoked with the original image as the first "
     76             "argument, the decompressed image as a second argument, and the "
     77             "name of the file where to write the metric value (as a single "
     78             "floating point number) as the third argument.",
     79             "");
     80   AddFlag(
     81       &print_more_stats, "print_more_stats",
     82       "Prints codec-specific stats. Not safe for concurrent benchmark runs.",
     83       false);
     84   AddFlag(&print_distance_percentiles, "print_distance_percentiles",
     85           "Prints distance percentiles for the corpus. Not safe for "
     86           "concurrent benchmark runs.",
     87           false);
     88   AddFlag(&silent_errors, "silent_errors",
     89           "If true, doesn't print error messages on compression or"
     90           " decompression errors. Errors counts are still visible in the"
     91           " 'Errors' column of the result table. Please note that depending"
     92           " depending on the JXL build settings, error messages and asserts"
     93           " from within the codec may be printed irrespective of this flag"
     94           " anyway, use release build to ensure no messages.",
     95           false);
     96   AddFlag(&save_compressed, "save_compressed",
     97           "Saves the compressed files for each input image and each codec.",
     98           false);
     99   AddFlag(&save_decompressed, "save_decompressed",
    100           "Saves the decompressed files as PNG for each input image "
    101           "and each codec.",
    102           false);
    103   AddString(&output_extension, "output_extension",
    104             "Extension (starting with dot) to use for saving output images.",
    105             ".png");
    106   AddString(&output_description, "output_description",
    107             "Color encoding (see ParseDescription; e.g. RGB_D65_SRG_Rel_709) "
    108             "for saving output images, "
    109             " defaults to sRGB.");
    110 
    111   AddFloat(&intensity_target, "intensity_target",
    112            "Intended viewing intensity target in nits. Defaults to 255 for "
    113            "SDR images, 4000 for HDR images (when the input image uses PQ or "
    114            "HLG transfer function)",
    115            0);
    116 
    117   AddString(&color_hints_string, "dec-hints",
    118             "Color encoding hints for the input images to encoder. Comma "
    119             "separated key=value pairs. The key color_space indicates "
    120             "ColorEncoding (see ParseDescription; e.g. RGB_D65_SRG_Rel_709) "
    121             "for input images without color encoding (such as PNM)");
    122 
    123   AddUnsigned(
    124       &override_bitdepth, "override_bitdepth",
    125       "If nonzero, store the given bit depth in the JPEG XL file metadata"
    126       " (1-32), instead of using the bit depth from the original input"
    127       " image.",
    128       0);
    129 
    130   AddDouble(&mul_output, "mul_output",
    131             "If nonzero, multiplies linear sRGB by this and clamps to 255",
    132             0.0);
    133   AddFlag(&save_heatmap, "save_heatmap", "Saves the heatmap images.", true);
    134   AddDouble(&heatmap_good, "heatmap_good",
    135             "If greater than zero, use this as the good "
    136             "threshold for creating heatmap images.",
    137             0.0);
    138   AddDouble(&heatmap_bad, "heatmap_bad",
    139             "If greater than zero, use this as the bad "
    140             "threshold for creating heatmap images.",
    141             0.0);
    142 
    143   AddFlag(&write_html_report, "write_html_report",
    144           "Creates an html report with original and compressed images.", false);
    145   AddFlag(&html_report_self_contained, "html_report_self_contained",
    146           "Base64-encode the images in the HTML report rather than use "
    147           "external file names. May cause very large HTML data size.",
    148           false);
    149   AddFlag(&html_report_use_decompressed, "html_report_use_decompressed",
    150           "Show the compressed image as decompressed to --output_extension.",
    151           true);
    152   AddFlag(&html_report_add_heatmap, "html_report_add_heatmap",
    153           "Add heatmaps to the image comparisons.", false);
    154 
    155   AddFlag(
    156       &markdown, "markdown",
    157       "Adds formatting around ASCII table to render correctly in Markdown based"
    158       " interfaces",
    159       true);
    160 
    161   AddFlag(&more_columns, "more_columns", "Print extra columns in the table",
    162           false);
    163 
    164   AddString(&originals_url, "originals_url",
    165             "Url prefix to serve original images from in the html report.");
    166   AddString(&output_dir, "output_dir",
    167             "If not empty, save compressed and decompressed "
    168             "images here.");
    169 
    170   AddSigned(&num_threads, "num_threads",
    171             "The number of threads for concurrent benchmarking. Defaults to "
    172             "1 thread per CPU core (if negative).",
    173             -1);
    174   AddSigned(&inner_threads, "inner_threads",
    175             "The number of extra threads per task. "
    176             "Defaults to occupy cores (if negative).",
    177             -1);
    178   AddUnsigned(&encode_reps, "encode_reps",
    179               "How many times to encode (>1 for more precise measurements). "
    180               "Defaults to 1.",
    181               1);
    182   AddUnsigned(&decode_reps, "decode_reps",
    183               "How many times to decode (>1 for more precise measurements). "
    184               "Defaults to 1.",
    185               1);
    186 
    187   AddString(&sample_tmp_dir, "sample_tmp_dir",
    188             "Directory to put samples from input images.");
    189 
    190   AddSigned(&num_samples, "num_samples", "How many sample areas to take.", 0);
    191   AddSigned(&sample_dimensions, "sample_dimensions",
    192             "How big areas to sample from the input.", 64);
    193 
    194   AddDouble(&error_pnorm, "error_pnorm",
    195             "smallest p norm for pooling butteraugli values", 3.0);
    196 
    197   AddFlag(&show_progress, "show_progress",
    198           "Show activity dots per completed file during benchmark.", false);
    199 
    200   AddFlag(&skip_butteraugli, "skip_butteraugli",
    201           "If true, doesn't compute distance metrics, only compression and"
    202           " decompression speed and size. Distance numbers shown in the"
    203           " table are invalid.",
    204           false);
    205 
    206   AddFlag(
    207       &decode_only, "decode_only",
    208       "If true, only decodes, and the input files must be compressed with a "
    209       "compatible format for the given codec(s). Only measures decompression "
    210       "speed and sizes, and can only use a single set of compatible decoders. "
    211       "Distance numbers and compression speeds shown in the table are invalid.",
    212       false);
    213 
    214   if (!AddCommandLineOptionsCustomCodec(this)) return false;
    215   if (!AddCommandLineOptionsJxlCodec(this)) return false;
    216   if (!AddCommandLineOptionsJPEGCodec(this)) return false;
    217 
    218 #ifdef BENCHMARK_PNG
    219   if (!AddCommandLineOptionsPNGCodec(this)) return false;
    220 #endif  // BENCHMARK_PNG
    221 #ifdef BENCHMARK_WEBP
    222   if (!AddCommandLineOptionsWebPCodec(this)) return false;
    223 #endif  // BENCHMARK_WEBP
    224 #ifdef BENCHMARK_AVIF
    225   if (!AddCommandLineOptionsAvifCodec(this)) return false;
    226 #endif  // BENCHMARK_AVIF
    227 
    228   return true;
    229 }
    230 
    231 Status BenchmarkArgs::ValidateArgs() {
    232   if (input.empty()) {
    233     fprintf(stderr, "Missing --input filename(s).\n");
    234     return false;
    235   }
    236   if (jxl::extras::CodecFromPath(output_extension) ==
    237       jxl::extras::Codec::kUnknown) {
    238     JXL_WARNING("Unrecognized output_extension %s, try .png",
    239                 output_extension.c_str());
    240     return false;  // already warned
    241   }
    242 
    243   // If empty, don't do anything; callers must only use output_encoding if
    244   // output_description is not empty.
    245   if (!output_description.empty()) {
    246     // Validate, but also create the profile (only needs to happen once).
    247     JxlColorEncoding output_encoding_external;
    248     if (!jxl::ParseDescription(output_description, &output_encoding_external)) {
    249       JXL_WARNING("Unrecognized output_description %s, try RGB_D65_SRG_Rel_Lin",
    250                   output_description.c_str());
    251       return false;  // already warned
    252     }
    253     JXL_RETURN_IF_ERROR(output_encoding.FromExternal(output_encoding_external));
    254     JXL_RETURN_IF_ERROR(!output_encoding.ICC().empty());
    255   }
    256 
    257   JXL_RETURN_IF_ERROR(ValidateArgsJxlCodec(this));
    258 
    259   if (print_details_csv) print_details = true;
    260 
    261   if (override_bitdepth > 32) {
    262     return JXL_FAILURE("override_bitdepth must be <= 32");
    263   }
    264 
    265   if (!color_hints_string.empty()) {
    266     std::vector<std::string> hints = SplitString(color_hints_string, ',');
    267     for (const auto& hint : hints) {
    268       std::vector<std::string> kv = SplitString(hint, '=');
    269       if (kv.size() != 2) {
    270         return JXL_FAILURE(
    271             "dec-hints key value pairs must have the form 'key=value'");
    272       }
    273       color_hints.Add(kv[0], kv[1]);
    274     }
    275   }
    276 
    277   return true;
    278 }
    279 
    280 }  // namespace tools
    281 }  // namespace jpegxl