diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /third_party/jpeg-xl/lib/jpegli/output_suspension_test.cc | |
parent | Initial commit. (diff) | |
download | thunderbird-upstream.tar.xz thunderbird-upstream.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/jpeg-xl/lib/jpegli/output_suspension_test.cc')
-rw-r--r-- | third_party/jpeg-xl/lib/jpegli/output_suspension_test.cc | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/third_party/jpeg-xl/lib/jpegli/output_suspension_test.cc b/third_party/jpeg-xl/lib/jpegli/output_suspension_test.cc new file mode 100644 index 0000000000..73db791727 --- /dev/null +++ b/third_party/jpeg-xl/lib/jpegli/output_suspension_test.cc @@ -0,0 +1,219 @@ +// Copyright (c) the JPEG XL Project Authors. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "lib/jpegli/encode.h" +#include "lib/jpegli/test_utils.h" +#include "lib/jpegli/testing.h" + +namespace jpegli { +namespace { + +static constexpr size_t kInitialBufferSize = 1024; +static constexpr size_t kFinalBufferSize = 18; + +struct DestinationManager { + jpeg_destination_mgr pub; + std::vector<uint8_t> buffer; + + DestinationManager() { + pub.init_destination = init_destination; + pub.empty_output_buffer = empty_output_buffer; + pub.term_destination = term_destination; + } + + void Rewind() { + pub.next_output_byte = buffer.data(); + pub.free_in_buffer = buffer.size(); + } + + void EmptyTo(std::vector<uint8_t>* output, size_t new_size = 0) { + output->insert(output->end(), buffer.data(), pub.next_output_byte); + if (new_size > 0) { + buffer.resize(new_size); + } + Rewind(); + } + + static void init_destination(j_compress_ptr cinfo) { + auto us = reinterpret_cast<DestinationManager*>(cinfo->dest); + us->buffer.resize(kInitialBufferSize); + us->Rewind(); + } + + static boolean empty_output_buffer(j_compress_ptr cinfo) { return FALSE; } + + static void term_destination(j_compress_ptr cinfo) {} +}; + +struct TestConfig { + TestImage input; + CompressParams jparams; + size_t buffer_size; + size_t lines_batch_size; +}; + +class OutputSuspensionTestParam : public ::testing::TestWithParam<TestConfig> { +}; + +TEST_P(OutputSuspensionTestParam, PixelData) { + jpeg_compress_struct cinfo = {}; + TestConfig config = GetParam(); + TestImage& input = config.input; + GeneratePixels(&input); + DestinationManager dest; + std::vector<uint8_t> compressed; + const auto try_catch_block = [&]() -> bool { + ERROR_HANDLER_SETUP(jpegli); + jpegli_create_compress(&cinfo); + cinfo.dest = reinterpret_cast<jpeg_destination_mgr*>(&dest); + + cinfo.image_width = input.xsize; + cinfo.image_height = input.ysize; + cinfo.input_components = input.components; + cinfo.in_color_space = JCS_RGB; + jpegli_set_defaults(&cinfo); + cinfo.comp_info[0].v_samp_factor = config.jparams.v_sampling[0]; + jpegli_set_progressive_level(&cinfo, 0); + cinfo.optimize_coding = FALSE; + jpegli_start_compress(&cinfo, TRUE); + + size_t stride = cinfo.image_width * cinfo.input_components; + std::vector<uint8_t> row_bytes(config.lines_batch_size * stride); + while (cinfo.next_scanline < cinfo.image_height) { + size_t lines_left = cinfo.image_height - cinfo.next_scanline; + size_t num_lines = std::min(config.lines_batch_size, lines_left); + memcpy(&row_bytes[0], &input.pixels[cinfo.next_scanline * stride], + num_lines * stride); + std::vector<JSAMPROW> rows(num_lines); + for (size_t i = 0; i < num_lines; ++i) { + rows[i] = &row_bytes[i * stride]; + } + size_t lines_done = 0; + while (lines_done < num_lines) { + lines_done += jpegli_write_scanlines(&cinfo, &rows[lines_done], + num_lines - lines_done); + if (lines_done < num_lines) { + dest.EmptyTo(&compressed, config.buffer_size); + } + } + } + dest.EmptyTo(&compressed, kFinalBufferSize); + jpegli_finish_compress(&cinfo); + dest.EmptyTo(&compressed); + return true; + }; + ASSERT_TRUE(try_catch_block()); + jpegli_destroy_compress(&cinfo); + TestImage output; + DecodeWithLibjpeg(CompressParams(), DecompressParams(), compressed, &output); + VerifyOutputImage(input, output, 2.5); +} + +TEST_P(OutputSuspensionTestParam, RawData) { + jpeg_compress_struct cinfo = {}; + TestConfig config = GetParam(); + if (config.lines_batch_size != 1) return; + TestImage& input = config.input; + input.color_space = JCS_YCbCr; + GeneratePixels(&input); + GenerateRawData(config.jparams, &input); + DestinationManager dest; + std::vector<uint8_t> compressed; + const auto try_catch_block = [&]() -> bool { + ERROR_HANDLER_SETUP(jpegli); + jpegli_create_compress(&cinfo); + cinfo.dest = reinterpret_cast<jpeg_destination_mgr*>(&dest); + cinfo.image_width = input.xsize; + cinfo.image_height = input.ysize; + cinfo.input_components = input.components; + cinfo.in_color_space = JCS_YCbCr; + jpegli_set_defaults(&cinfo); + cinfo.comp_info[0].v_samp_factor = config.jparams.v_sampling[0]; + jpegli_set_progressive_level(&cinfo, 0); + cinfo.optimize_coding = FALSE; + cinfo.raw_data_in = TRUE; + jpegli_start_compress(&cinfo, TRUE); + + std::vector<std::vector<uint8_t>> raw_data = input.raw_data; + size_t max_lines = config.jparams.max_v_sample() * DCTSIZE; + std::vector<std::vector<JSAMPROW>> rowdata(cinfo.num_components); + std::vector<JSAMPARRAY> data(cinfo.num_components); + for (int c = 0; c < cinfo.num_components; ++c) { + rowdata[c].resize(config.jparams.v_samp(c) * DCTSIZE); + data[c] = &rowdata[c][0]; + } + while (cinfo.next_scanline < cinfo.image_height) { + for (int c = 0; c < cinfo.num_components; ++c) { + size_t cwidth = cinfo.comp_info[c].width_in_blocks * DCTSIZE; + size_t cheight = cinfo.comp_info[c].height_in_blocks * DCTSIZE; + size_t num_lines = config.jparams.v_samp(c) * DCTSIZE; + size_t y0 = (cinfo.next_scanline / max_lines) * num_lines; + for (size_t i = 0; i < num_lines; ++i) { + rowdata[c][i] = + (y0 + i < cheight ? &raw_data[c][(y0 + i) * cwidth] : nullptr); + } + } + while (jpegli_write_raw_data(&cinfo, &data[0], max_lines) == 0) { + dest.EmptyTo(&compressed, config.buffer_size); + } + } + dest.EmptyTo(&compressed, kFinalBufferSize); + jpegli_finish_compress(&cinfo); + dest.EmptyTo(&compressed); + return true; + }; + try_catch_block(); + jpegli_destroy_compress(&cinfo); + DecompressParams dparams; + dparams.output_mode = RAW_DATA; + TestImage output; + DecodeWithLibjpeg(CompressParams(), dparams, compressed, &output); + VerifyOutputImage(input, output, 3.5); +} + +std::vector<TestConfig> GenerateTests() { + std::vector<TestConfig> all_tests; + const size_t xsize0 = 1920; + const size_t ysize0 = 1080; + for (int dysize : {0, 1, 8, 9}) { + for (int v_sampling : {1, 2}) { + for (int nlines : {1, 8, 117}) { + for (int bufsize : {1, 16, 16 << 10}) { + TestConfig config; + config.lines_batch_size = nlines; + config.buffer_size = bufsize; + config.input.xsize = xsize0; + config.input.ysize = ysize0 + dysize; + config.jparams.h_sampling = {1, 1, 1}; + config.jparams.v_sampling = {v_sampling, 1, 1}; + all_tests.push_back(config); + } + } + } + } + return all_tests; +} + +std::ostream& operator<<(std::ostream& os, const TestConfig& c) { + os << c.input; + os << c.jparams; + os << "Lines" << c.lines_batch_size; + os << "BufSize" << c.buffer_size; + return os; +} + +std::string TestDescription( + const testing::TestParamInfo<OutputSuspensionTestParam::ParamType>& info) { + std::stringstream name; + name << info.param; + return name.str(); +} + +JPEGLI_INSTANTIATE_TEST_SUITE_P(OutputSuspensionTest, OutputSuspensionTestParam, + testing::ValuesIn(GenerateTests()), + TestDescription); + +} // namespace +} // namespace jpegli |