tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

output_suspension_test.cc (7623B)


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