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 }