// 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.
// A destination manager that empties its output buffer into a SourceManager's // input buffer. The buffer size is kept short because empty_output_buffer() is // called only when the output buffer is full, and we want to update the decoder // input frequently to demonstrate that streaming works.
constexpr size_t kOutputBufferSize = 1024; struct DestinationManager {
jpeg_destination_mgr pub;
std::vector<uint8_t> buffer;
SourceManager* dest;
size_t stride = cinfo.image_width * cinfo.input_components;
size_t iMCU_height = 8 * cinfo.max_v_samp_factor;
std::vector<uint8_t> row_bytes(iMCU_height * stride);
size_t y_in = 0;
size_t y_out = 0; while (y_in < cinfo.image_height) { // Feed one iMCU row at a time to the compressor.
size_t lines_in = std::min(iMCU_height, cinfo.image_height - y_in);
memcpy(row_bytes.data(), &input.pixels[y_in * stride], lines_in * stride);
std::vector<JSAMPROW> rows_in(lines_in); for (size_t i = 0; i < lines_in; ++i) {
rows_in[i] = &row_bytes[i * stride];
}
EXPECT_EQ(lines_in,
jpegli_write_scanlines(&cinfo, rows_in.data(), lines_in));
y_in += lines_in; if (y_in == cinfo.image_height) {
jpegli_finish_compress(&cinfo);
}
// Atfer the first iMCU row, we don't yet expect any output because the // compressor delays processing to have context rows after the iMCU row. if (y_in < std::min<size_t>(2 * iMCU_height, cinfo.image_height)) { continue;
}
// After two iMCU rows, the compressor has started emitting compressed // data. We check here that at least the scan header was output, because // we expect that the compressor's output buffer was filled at least once // while emitting the first compressed iMCU row. if (y_in == std::min<size_t>(2 * iMCU_height, cinfo.image_height)) {
EXPECT_EQ(JPEG_REACHED_SOS,
jpegli_read_header(&dinfo, /*require_image=*/TRUE));
output.xsize = dinfo.image_width;
output.ysize = dinfo.image_height;
output.components = dinfo.num_components;
EXPECT_EQ(output.xsize, input.xsize);
EXPECT_EQ(output.ysize, input.ysize);
EXPECT_EQ(output.components, input.components);
EXPECT_TRUE(jpegli_start_decompress(&dinfo));
output.pixels.resize(output.ysize * stride); if (y_in < cinfo.image_height) { continue;
}
}
// After six iMCU rows, the compressor has emitted five iMCU rows of // compressed data, of which we expect four full iMCU row of compressed // data to be in the decoder's input buffer, but since the decoder also // needs context rows for upsampling and smoothing, we don't expect any // output to be ready yet. if (y_in < 7 * iMCU_height && y_in < cinfo.image_height) { continue;
}
// After five iMCU rows, we expect the decoder to have rendered the output // with four iMCU rows of delay. // TODO(szabadka) Reduce the processing delay in the decoder if possible.
size_t lines_out =
(y_in == cinfo.image_height ? cinfo.image_height - y_out
: iMCU_height);
std::vector<JSAMPROW> rows_out(lines_out); for (size_t i = 0; i < lines_out; ++i) {
rows_out[i] = reinterpret_cast<JSAMPLE*>(&output.pixels[(y_out + i) * stride]);
}
EXPECT_EQ(lines_out,
jpegli_read_scanlines(&dinfo, rows_out.data(), lines_out));
VerifyOutputImage(input, output, y_out, lines_out, 3.8f);
y_out += lines_out;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.