libjxl

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

output_suspension_test.cc (7323B)


      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 "lib/jpegli/encode.h"
      7 #include "lib/jpegli/test_utils.h"
      8 #include "lib/jpegli/testing.h"
      9 
     10 namespace jpegli {
     11 namespace {
     12 
     13 constexpr size_t kInitialBufferSize = 1024;
     14 constexpr size_t kFinalBufferSize = 18;
     15 
     16 struct DestinationManager {
     17   jpeg_destination_mgr pub;
     18   std::vector<uint8_t> buffer;
     19 
     20   DestinationManager() {
     21     pub.init_destination = init_destination;
     22     pub.empty_output_buffer = empty_output_buffer;
     23     pub.term_destination = term_destination;
     24   }
     25 
     26   void Rewind() {
     27     pub.next_output_byte = buffer.data();
     28     pub.free_in_buffer = buffer.size();
     29   }
     30 
     31   void EmptyTo(std::vector<uint8_t>* output, size_t new_size = 0) {
     32     output->insert(output->end(), buffer.data(), pub.next_output_byte);
     33     if (new_size > 0) {
     34       buffer.resize(new_size);
     35     }
     36     Rewind();
     37   }
     38 
     39   static void init_destination(j_compress_ptr cinfo) {
     40     auto* us = reinterpret_cast<DestinationManager*>(cinfo->dest);
     41     us->buffer.resize(kInitialBufferSize);
     42     us->Rewind();
     43   }
     44 
     45   static boolean empty_output_buffer(j_compress_ptr cinfo) { return FALSE; }
     46 
     47   static void term_destination(j_compress_ptr cinfo) {}
     48 };
     49 
     50 struct TestConfig {
     51   TestImage input;
     52   CompressParams jparams;
     53   size_t buffer_size;
     54   size_t lines_batch_size;
     55 };
     56 
     57 class OutputSuspensionTestParam : public ::testing::TestWithParam<TestConfig> {
     58 };
     59 
     60 TEST_P(OutputSuspensionTestParam, PixelData) {
     61   jpeg_compress_struct cinfo = {};
     62   TestConfig config = GetParam();
     63   TestImage& input = config.input;
     64   GeneratePixels(&input);
     65   DestinationManager dest;
     66   std::vector<uint8_t> compressed;
     67   const auto try_catch_block = [&]() -> bool {
     68     ERROR_HANDLER_SETUP(jpegli);
     69     jpegli_create_compress(&cinfo);
     70     cinfo.dest = reinterpret_cast<jpeg_destination_mgr*>(&dest);
     71 
     72     cinfo.image_width = input.xsize;
     73     cinfo.image_height = input.ysize;
     74     cinfo.input_components = input.components;
     75     cinfo.in_color_space = JCS_RGB;
     76     jpegli_set_defaults(&cinfo);
     77     cinfo.comp_info[0].v_samp_factor = config.jparams.v_sampling[0];
     78     jpegli_set_progressive_level(&cinfo, 0);
     79     cinfo.optimize_coding = FALSE;
     80     jpegli_start_compress(&cinfo, TRUE);
     81 
     82     size_t stride = cinfo.image_width * cinfo.input_components;
     83     std::vector<uint8_t> row_bytes(config.lines_batch_size * stride);
     84     while (cinfo.next_scanline < cinfo.image_height) {
     85       size_t lines_left = cinfo.image_height - cinfo.next_scanline;
     86       size_t num_lines = std::min(config.lines_batch_size, lines_left);
     87       memcpy(row_bytes.data(), &input.pixels[cinfo.next_scanline * stride],
     88              num_lines * stride);
     89       std::vector<JSAMPROW> rows(num_lines);
     90       for (size_t i = 0; i < num_lines; ++i) {
     91         rows[i] = &row_bytes[i * stride];
     92       }
     93       size_t lines_done = 0;
     94       while (lines_done < num_lines) {
     95         lines_done += jpegli_write_scanlines(&cinfo, &rows[lines_done],
     96                                              num_lines - lines_done);
     97         if (lines_done < num_lines) {
     98           dest.EmptyTo(&compressed, config.buffer_size);
     99         }
    100       }
    101     }
    102     dest.EmptyTo(&compressed, kFinalBufferSize);
    103     jpegli_finish_compress(&cinfo);
    104     dest.EmptyTo(&compressed);
    105     return true;
    106   };
    107   ASSERT_TRUE(try_catch_block());
    108   jpegli_destroy_compress(&cinfo);
    109   TestImage output;
    110   DecodeWithLibjpeg(CompressParams(), DecompressParams(), compressed, &output);
    111   VerifyOutputImage(input, output, 2.5);
    112 }
    113 
    114 TEST_P(OutputSuspensionTestParam, RawData) {
    115   jpeg_compress_struct cinfo = {};
    116   TestConfig config = GetParam();
    117   if (config.lines_batch_size != 1) return;
    118   TestImage& input = config.input;
    119   input.color_space = JCS_YCbCr;
    120   GeneratePixels(&input);
    121   GenerateRawData(config.jparams, &input);
    122   DestinationManager dest;
    123   std::vector<uint8_t> compressed;
    124   const auto try_catch_block = [&]() -> bool {
    125     ERROR_HANDLER_SETUP(jpegli);
    126     jpegli_create_compress(&cinfo);
    127     cinfo.dest = reinterpret_cast<jpeg_destination_mgr*>(&dest);
    128     cinfo.image_width = input.xsize;
    129     cinfo.image_height = input.ysize;
    130     cinfo.input_components = input.components;
    131     cinfo.in_color_space = JCS_YCbCr;
    132     jpegli_set_defaults(&cinfo);
    133     cinfo.comp_info[0].v_samp_factor = config.jparams.v_sampling[0];
    134     jpegli_set_progressive_level(&cinfo, 0);
    135     cinfo.optimize_coding = FALSE;
    136     cinfo.raw_data_in = TRUE;
    137     jpegli_start_compress(&cinfo, TRUE);
    138 
    139     std::vector<std::vector<uint8_t>> raw_data = input.raw_data;
    140     size_t max_lines = config.jparams.max_v_sample() * DCTSIZE;
    141     std::vector<std::vector<JSAMPROW>> rowdata(cinfo.num_components);
    142     std::vector<JSAMPARRAY> data(cinfo.num_components);
    143     for (int c = 0; c < cinfo.num_components; ++c) {
    144       rowdata[c].resize(config.jparams.v_samp(c) * DCTSIZE);
    145       data[c] = rowdata[c].data();
    146     }
    147     while (cinfo.next_scanline < cinfo.image_height) {
    148       for (int c = 0; c < cinfo.num_components; ++c) {
    149         size_t cwidth = cinfo.comp_info[c].width_in_blocks * DCTSIZE;
    150         size_t cheight = cinfo.comp_info[c].height_in_blocks * DCTSIZE;
    151         size_t num_lines = config.jparams.v_samp(c) * DCTSIZE;
    152         size_t y0 = (cinfo.next_scanline / max_lines) * num_lines;
    153         for (size_t i = 0; i < num_lines; ++i) {
    154           rowdata[c][i] =
    155               (y0 + i < cheight ? &raw_data[c][(y0 + i) * cwidth] : nullptr);
    156         }
    157       }
    158       while (jpegli_write_raw_data(&cinfo, data.data(), max_lines) == 0) {
    159         dest.EmptyTo(&compressed, config.buffer_size);
    160       }
    161     }
    162     dest.EmptyTo(&compressed, kFinalBufferSize);
    163     jpegli_finish_compress(&cinfo);
    164     dest.EmptyTo(&compressed);
    165     return true;
    166   };
    167   try_catch_block();
    168   jpegli_destroy_compress(&cinfo);
    169   DecompressParams dparams;
    170   dparams.output_mode = RAW_DATA;
    171   TestImage output;
    172   DecodeWithLibjpeg(CompressParams(), dparams, compressed, &output);
    173   VerifyOutputImage(input, output, 3.5);
    174 }
    175 
    176 std::vector<TestConfig> GenerateTests() {
    177   std::vector<TestConfig> all_tests;
    178   const size_t xsize0 = 1920;
    179   const size_t ysize0 = 1080;
    180   for (int dysize : {0, 1, 8, 9}) {
    181     for (int v_sampling : {1, 2}) {
    182       for (int nlines : {1, 8, 117}) {
    183         for (int bufsize : {1, 16, 16 << 10}) {
    184           TestConfig config;
    185           config.lines_batch_size = nlines;
    186           config.buffer_size = bufsize;
    187           config.input.xsize = xsize0;
    188           config.input.ysize = ysize0 + dysize;
    189           config.jparams.h_sampling = {1, 1, 1};
    190           config.jparams.v_sampling = {v_sampling, 1, 1};
    191           all_tests.push_back(config);
    192         }
    193       }
    194     }
    195   }
    196   return all_tests;
    197 }
    198 
    199 std::ostream& operator<<(std::ostream& os, const TestConfig& c) {
    200   os << c.input;
    201   os << c.jparams;
    202   os << "Lines" << c.lines_batch_size;
    203   os << "BufSize" << c.buffer_size;
    204   return os;
    205 }
    206 
    207 std::string TestDescription(
    208     const testing::TestParamInfo<OutputSuspensionTestParam::ParamType>& info) {
    209   std::stringstream name;
    210   name << info.param;
    211   return name.str();
    212 }
    213 
    214 JPEGLI_INSTANTIATE_TEST_SUITE_P(OutputSuspensionTest, OutputSuspensionTestParam,
    215                                 testing::ValuesIn(GenerateTests()),
    216                                 TestDescription);
    217 
    218 }  // namespace
    219 }  // namespace jpegli