libjxl

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

fast_lossless_main.cc (3380B)


      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 <stdio.h>
      7 #include <stdlib.h>
      8 #include <string.h>
      9 
     10 #include <atomic>
     11 #include <chrono>
     12 #include <thread>
     13 #include <vector>
     14 
     15 #include "lib/jxl/enc_fast_lossless.h"
     16 #include "lodepng.h"
     17 #include "pam-input.h"
     18 
     19 int main(int argc, char** argv) {
     20   if (argc < 3) {
     21     fprintf(stderr,
     22             "Usage: %s in.png out.jxl [effort] [num_reps] [num_threads]\n",
     23             argv[0]);
     24     return 1;
     25   }
     26 
     27   const char* in = argv[1];
     28   const char* out = argv[2];
     29   int effort = argc >= 4 ? atoi(argv[3]) : 2;
     30   size_t num_reps = argc >= 5 ? atoi(argv[4]) : 1;
     31   size_t num_threads = argc >= 6 ? atoi(argv[5]) : 0;
     32 
     33   if (effort < 0 || effort > 127) {
     34     fprintf(
     35         stderr,
     36         "Effort should be between 0 and 127 (default is 2, more is slower)\n");
     37     return 1;
     38   }
     39 
     40   unsigned char* png;
     41   unsigned w;
     42   unsigned h;
     43   unsigned error = lodepng_decode32_file(&png, &w, &h, in);
     44 
     45   size_t nb_chans = 4;
     46   size_t bitdepth = 8;
     47   size_t width = w;
     48   size_t height = h;
     49   if (error && !DecodePAM(in, &png, &width, &height, &nb_chans, &bitdepth)) {
     50     fprintf(stderr, "lodepng error %u: %s\n", error, lodepng_error_text(error));
     51     return 1;
     52   }
     53 
     54   auto parallel_runner = [](void* num_threads_ptr, void* opaque,
     55                             void fun(void*, size_t), size_t count) {
     56     size_t num_threads = *static_cast<size_t*>(num_threads_ptr);
     57     if (num_threads == 0) {
     58       num_threads = std::thread::hardware_concurrency();
     59     }
     60     if (num_threads > count) {
     61       num_threads = count;
     62     }
     63     if (num_threads == 1) {
     64       for (size_t i = 0; i < count; i++) {
     65         fun(opaque, i);
     66       }
     67     } else {
     68       std::atomic<int> task{0};
     69       std::vector<std::thread> threads;
     70       for (size_t i = 0; i < num_threads; i++) {
     71         threads.push_back(std::thread([count, opaque, fun, &task]() {
     72           while (true) {
     73             int t = task++;
     74             if (t >= count) break;
     75             fun(opaque, t);
     76           }
     77         }));
     78       }
     79       for (auto& t : threads) t.join();
     80     }
     81   };
     82 
     83   size_t encoded_size = 0;
     84   unsigned char* encoded = nullptr;
     85   size_t stride = width * nb_chans * (bitdepth > 8 ? 2 : 1);
     86 
     87   auto start = std::chrono::high_resolution_clock::now();
     88   for (size_t _ = 0; _ < num_reps; _++) {
     89     free(encoded);
     90     encoded_size = JxlFastLosslessEncode(
     91         png, width, stride, height, nb_chans, bitdepth,
     92         /*big_endian=*/true, effort, &encoded, &num_threads, +parallel_runner);
     93   }
     94   auto stop = std::chrono::high_resolution_clock::now();
     95   if (num_reps > 1) {
     96     float us =
     97         std::chrono::duration_cast<std::chrono::microseconds>(stop - start)
     98             .count();
     99     size_t pixels = size_t{width} * size_t{height} * num_reps;
    100     float mps = pixels / us;
    101     fprintf(stderr, "%10.3f MP/s\n", mps);
    102     fprintf(stderr, "%10.3f bits/pixel\n",
    103             encoded_size * 8.0 / static_cast<float>(width) /
    104                 static_cast<float>(height));
    105   }
    106 
    107   FILE* o = fopen(out, "wb");
    108   if (!o) {
    109     fprintf(stderr, "error opening %s: %s\n", out, strerror(errno));
    110     return 1;
    111   }
    112   if (fwrite(encoded, 1, encoded_size, o) != encoded_size) {
    113     fprintf(stderr, "error writing to %s: %s\n", out, strerror(errno));
    114   }
    115   fclose(o);
    116 }