benchmark_codec.cc (6143B)
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_codec.h" 7 8 #include <jxl/types.h> 9 #include <stdint.h> 10 #include <stdlib.h> 11 #include <string.h> 12 13 #include <string> 14 #include <utility> 15 #include <vector> 16 17 #include "lib/extras/packed_image_convert.h" 18 #include "lib/extras/time.h" 19 #include "lib/jxl/base/status.h" 20 #include "lib/jxl/color_encoding_internal.h" 21 #include "lib/jxl/image.h" 22 #include "lib/jxl/image_bundle.h" 23 #include "lib/jxl/image_ops.h" 24 #include "tools/benchmark/benchmark_args.h" 25 #include "tools/benchmark/benchmark_codec_custom.h" 26 #include "tools/benchmark/benchmark_codec_jpeg.h" 27 #include "tools/benchmark/benchmark_codec_jxl.h" 28 #include "tools/benchmark/benchmark_stats.h" 29 #include "tools/speed_stats.h" 30 #include "tools/thread_pool_internal.h" 31 32 #ifdef BENCHMARK_PNG 33 #include "tools/benchmark/benchmark_codec_png.h" 34 #endif // BENCHMARK_PNG 35 36 #ifdef BENCHMARK_WEBP 37 #include "tools/benchmark/benchmark_codec_webp.h" 38 #endif // BENCHMARK_WEBP 39 40 #ifdef BENCHMARK_AVIF 41 #include "tools/benchmark/benchmark_codec_avif.h" 42 #endif // BENCHMARK_AVIF 43 44 namespace jpegxl { 45 namespace tools { 46 47 using ::jxl::Image3F; 48 49 void ImageCodec::ParseParameters(const std::string& parameters) { 50 params_ = parameters; 51 std::vector<std::string> parts = SplitString(parameters, ':'); 52 for (size_t i = 0; i < parts.size(); ++i) { 53 if (!ParseParam(parts[i])) { 54 JXL_ABORT("Invalid parameter %s", parts[i].c_str()); 55 } 56 } 57 } 58 59 Status ImageCodec::ParseParam(const std::string& param) { 60 if (param[0] == 'q') { // libjpeg-style quality, [0,100] 61 const std::string quality_param = param.substr(1); 62 char* end; 63 const float q_target = strtof(quality_param.c_str(), &end); 64 if (end == quality_param.c_str() || 65 end != quality_param.c_str() + quality_param.size()) { 66 return false; 67 } 68 q_target_ = q_target; 69 return true; 70 } 71 if (param[0] == 'd') { // butteraugli distance 72 const std::string distance_param = param.substr(1); 73 char* end; 74 const float butteraugli_target = strtof(distance_param.c_str(), &end); 75 if (end == distance_param.c_str() || 76 end != distance_param.c_str() + distance_param.size()) { 77 return false; 78 } 79 butteraugli_target_ = butteraugli_target; 80 return true; 81 } else if (param[0] == 'r') { 82 bitrate_target_ = strtof(param.substr(1).c_str(), nullptr); 83 return true; 84 } 85 return false; 86 } 87 88 // Low-overhead "codec" for measuring benchmark overhead. 89 class NoneCodec : public ImageCodec { 90 public: 91 explicit NoneCodec(const BenchmarkArgs& args) : ImageCodec(args) {} 92 Status ParseParam(const std::string& param) override { return true; } 93 94 Status Compress(const std::string& filename, const PackedPixelFile& ppf, 95 ThreadPool* pool, std::vector<uint8_t>* compressed, 96 jpegxl::tools::SpeedStats* speed_stats) override { 97 const double start = jxl::Now(); 98 // Encode image size so we "decompress" something of the same size, as 99 // required by butteraugli. 100 const uint32_t xsize = ppf.xsize(); 101 const uint32_t ysize = ppf.ysize(); 102 compressed->resize(8); 103 memcpy(compressed->data(), &xsize, 4); 104 memcpy(compressed->data() + 4, &ysize, 4); 105 const double end = jxl::Now(); 106 speed_stats->NotifyElapsed(end - start); 107 return true; 108 } 109 110 Status Decompress(const std::string& filename, 111 const Span<const uint8_t> compressed, ThreadPool* pool, 112 PackedPixelFile* ppf, 113 jpegxl::tools::SpeedStats* speed_stats) override { 114 CodecInOut io; 115 JXL_RETURN_IF_ERROR( 116 Decompress(filename, compressed, pool, &io, speed_stats)); 117 JxlPixelFormat format{0, JXL_TYPE_UINT16, JXL_NATIVE_ENDIAN, 0}; 118 return jxl::extras::ConvertCodecInOutToPackedPixelFile( 119 io, format, io.Main().c_current(), pool, ppf); 120 }; 121 122 static Status Decompress(const std::string& filename, 123 const Span<const uint8_t> compressed, 124 ThreadPool* pool, CodecInOut* io, 125 jpegxl::tools::SpeedStats* speed_stats) { 126 const double start = jxl::Now(); 127 JXL_ASSERT(compressed.size() == 8); 128 uint32_t xsize; 129 uint32_t ysize; 130 memcpy(&xsize, compressed.data(), 4); 131 memcpy(&ysize, compressed.data() + 4, 4); 132 JXL_ASSIGN_OR_RETURN(Image3F image, Image3F::Create(xsize, ysize)); 133 ZeroFillImage(&image); 134 io->metadata.m.SetFloat32Samples(); 135 io->metadata.m.color_encoding = ColorEncoding::SRGB(); 136 io->SetFromImage(std::move(image), io->metadata.m.color_encoding); 137 const double end = jxl::Now(); 138 speed_stats->NotifyElapsed(end - start); 139 return true; 140 } 141 142 void GetMoreStats(BenchmarkStats* stats) override {} 143 }; 144 145 ImageCodecPtr CreateImageCodec(const std::string& description) { 146 std::string name = description; 147 std::string parameters; 148 size_t colon = description.find(':'); 149 if (colon < description.size()) { 150 name = description.substr(0, colon); 151 parameters = description.substr(colon + 1); 152 } 153 ImageCodecPtr result; 154 if (name == "jxl") { 155 result.reset(CreateNewJxlCodec(*Args())); 156 #if !defined(__wasm__) 157 } else if (name == "custom") { 158 result.reset(CreateNewCustomCodec(*Args())); 159 #endif 160 } else if (name == "jpeg") { 161 result.reset(CreateNewJPEGCodec(*Args())); 162 #ifdef BENCHMARK_PNG 163 } else if (name == "png") { 164 result.reset(CreateNewPNGCodec(*Args())); 165 #endif // BENCHMARK_PNG 166 } else if (name == "none") { 167 result.reset(new NoneCodec(*Args())); 168 #ifdef BENCHMARK_WEBP 169 } else if (name == "webp") { 170 result.reset(CreateNewWebPCodec(*Args())); 171 #endif // BENCHMARK_WEBP 172 #ifdef BENCHMARK_AVIF 173 } else if (name == "avif") { 174 result.reset(CreateNewAvifCodec(*Args())); 175 #endif // BENCHMARK_AVIF 176 } 177 if (!result.get()) { 178 JXL_ABORT("Unknown image codec: %s", name.c_str()); 179 } 180 result->set_description(description); 181 if (!parameters.empty()) result->ParseParameters(parameters); 182 return result; 183 } 184 185 } // namespace tools 186 } // namespace jpegxl