// 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/jxl/quant_weights.h"
// These templates are not found via ADL. using hwy::HWY_NAMESPACE::Lt; using hwy::HWY_NAMESPACE::MulAdd; using hwy::HWY_NAMESPACE::Sqrt;
// kQuantWeights[N * N * c + N * y + x] is the relative weight of the (x, y) // coefficient in component c. Higher weights correspond to finer quantization // intervals and more bits spent in encoding.
static constexpr constfloat kAlmostZero = 1e-8f;
void GetQuantWeightsDCT2(const QuantEncoding::DCT2Weights& dct2weights, float* weights) { for (size_t c = 0; c < 3; c++) {
size_t start = c * 64;
weights[start] = 0xBAD;
weights[start + 1] = weights[start + 8] = dct2weights[c][0];
weights[start + 9] = dct2weights[c][1]; for (size_t y = 0; y < 2; y++) { for (size_t x = 0; x < 2; x++) {
weights[start + y * 8 + x + 2] = dct2weights[c][2];
weights[start + (y + 2) * 8 + x] = dct2weights[c][2];
}
} for (size_t y = 0; y < 2; y++) { for (size_t x = 0; x < 2; x++) {
weights[start + (y + 2) * 8 + x + 2] = dct2weights[c][3];
}
} for (size_t y = 0; y < 4; y++) { for (size_t x = 0; x < 4; x++) {
weights[start + y * 8 + x + 4] = dct2weights[c][4];
weights[start + (y + 4) * 8 + x] = dct2weights[c][4];
}
} for (size_t y = 0; y < 4; y++) { for (size_t x = 0; x < 4; x++) {
weights[start + (y + 4) * 8 + x + 4] = dct2weights[c][5];
}
}
}
}
void GetQuantWeightsIdentity(const QuantEncoding::IdWeights& idweights, float* weights) { for (size_t c = 0; c < 3; c++) { for (int i = 0; i < 64; i++) {
weights[64 * c + i] = idweights[c][0];
}
weights[64 * c + 1] = idweights[c][1];
weights[64 * c + 8] = idweights[c][1];
weights[64 * c + 9] = idweights[c][2];
}
}
auto frac = Sub(scaled_pos, ConvertTo(DF4(), idx));
// TODO(veluca): in theory, this could be done with 8 TableLookupBytes, but // it's probably slower. auto a = GatherIndex(DF4(), array, idx); auto b = GatherIndex(DF4(), array + 1, idx);
constexpr float lo = 0.8517778890324296;
constexpr float hi = 12.97166202570235f - lo + 1e-6f; for (size_t c = 0; c < 3; c++) { float bands[4];
bands[0] = encoding.afv_weights[c][5]; if (bands[0] < kAlmostZero) return JXL_FAILURE("Invalid AFV bands"); for (size_t i = 1; i < 4; i++) {
bands[i] = bands[i - 1] * Mult(encoding.afv_weights[c][i + 5]); if (bands[i] < kAlmostZero) return JXL_FAILURE("Invalid AFV bands");
}
size_t start = c * 64; auto set_weight = [&start, &weights](size_t x, size_t y, float val) {
weights[start + y * 8 + x] = val;
};
weights[start] = 1; // Not used, but causes MSAN error otherwise. // Weights for (0, 1) and (1, 0).
set_weight(0, 1, encoding.afv_weights[c][0]);
set_weight(1, 0, encoding.afv_weights[c][1]); // AFV special weights for 3-pixel corner.
set_weight(0, 2, encoding.afv_weights[c][2]);
set_weight(2, 0, encoding.afv_weights[c][3]);
set_weight(2, 2, encoding.afv_weights[c][4]);
// All other AFV weights. for (size_t y = 0; y < 4; y++) { for (size_t x = 0; x < 4; x++) { if (x < 2 && y < 2) continue;
JXL_ASSIGN_OR_RETURN( float val, Interpolate(kFreqs[y * 4 + x] - lo, hi, bands, 4));
set_weight(2 * x, 2 * y, val);
}
}
// Put 4x8 weights in odd rows, except (1, 0). for (size_t y = 0; y < kBlockDim / 2; y++) { for (size_t x = 0; x < kBlockDim; x++) { if (x == 0 && y == 0) continue;
weights[c * num + (2 * y + 1) * kBlockDim + x] =
weights4x8[c * 32 + y * 8 + x];
}
} // Put 4x4 weights in even rows / odd columns, except (0, 1). for (size_t y = 0; y < kBlockDim / 2; y++) { for (size_t x = 0; x < kBlockDim / 2; x++) { if (x == 0 && y == 0) continue;
weights[c * num + (2 * y) * kBlockDim + 2 * x + 1] =
weights4x4[c * 16 + y * 4 + x];
}
}
} break;
}
}
size_t prev_pos = *pos;
HWY_CAPPED(float, 64) d; for (size_t i = 0; i < num * 3; i += Lanes(d)) { auto inv_val = LoadU(d, weights.data() + i); if (JXL_UNLIKELY(!AllFalse(d, Ge(inv_val, Set(d, 1.0f / kAlmostZero))) ||
!AllFalse(d, Lt(inv_val, Set(d, kAlmostZero))))) { return JXL_FAILURE("Invalid quantization table");
} auto val = Div(Set(d, 1.0f), inv_val);
StoreU(val, d, table + *pos + i);
StoreU(inv_val, d, inv_table + *pos + i);
}
(*pos) += 3 * num;
// Ensure that the lowest frequencies have a 0 inverse table. // This does not affect en/decoding, but allows AC strategy selection to be // slightly simpler.
size_t xs = DequantMatrices::required_size_x[quant_table_idx];
size_t ys = DequantMatrices::required_size_y[quant_table_idx];
CoefficientLayout(&ys, &xs); for (size_t c = 0; c < 3; c++) { for (size_t y = 0; y < ys; y++) { for (size_t x = 0; x < xs; x++) {
inv_table[prev_pos + c * ys * xs * kDCTBlockSize + y * kBlockDim * xs +
x] = 0;
}
}
} returntrue;
}
Status DecodeDctParams(BitReader* br, DctQuantWeightParams* params) {
params->num_distance_bands =
br->ReadFixedBits<DctQuantWeightParams::kLog2MaxDistanceBands>() + 1; for (size_t c = 0; c < 3; c++) { for (size_t i = 0; i < params->num_distance_bands; i++) {
JXL_RETURN_IF_ERROR(F16Coder::Read(br, ¶ms->distance_bands[c][i]));
} if (params->distance_bands[c][0] < kAlmostZero) { return JXL_FAILURE("Distance band seed is too small");
}
params->distance_bands[c][0] *= 64.0f;
} returntrue;
}
Status Decode(JxlMemoryManager* memory_manager, BitReader* br,
QuantEncoding* encoding, size_t required_size_x,
size_t required_size_y, size_t idx,
ModularFrameDecoder* modular_frame_decoder) {
size_t required_size = required_size_x * required_size_y;
required_size_x *= kBlockDim;
required_size_y *= kBlockDim; int mode = br->ReadFixedBits<kLog2NumQuantModes>(); switch (mode) { case QuantEncoding::kQuantModeLibrary: {
encoding->predefined = br->ReadFixedBits<kCeilLog2NumPredefinedTables>(); if (encoding->predefined >= kNumPredefinedTables) { return JXL_FAILURE("Invalid predefined table");
} break;
} case QuantEncoding::kQuantModeID: { if (required_size != 1) return JXL_FAILURE("Invalid mode"); for (size_t c = 0; c < 3; c++) { for (size_t i = 0; i < 3; i++) {
JXL_RETURN_IF_ERROR(F16Coder::Read(br, &encoding->idweights[c][i])); if (std::abs(encoding->idweights[c][i]) < kAlmostZero) { return JXL_FAILURE("ID Quantizer is too small");
}
encoding->idweights[c][i] *= 64;
}
} break;
} case QuantEncoding::kQuantModeDCT2: { if (required_size != 1) return JXL_FAILURE("Invalid mode"); for (size_t c = 0; c < 3; c++) { for (size_t i = 0; i < 6; i++) {
JXL_RETURN_IF_ERROR(F16Coder::Read(br, &encoding->dct2weights[c][i])); if (std::abs(encoding->dct2weights[c][i]) < kAlmostZero) { return JXL_FAILURE("Quantizer is too small");
}
encoding->dct2weights[c][i] *= 64;
}
} break;
} case QuantEncoding::kQuantModeDCT4X8: { if (required_size != 1) return JXL_FAILURE("Invalid mode"); for (size_t c = 0; c < 3; c++) {
JXL_RETURN_IF_ERROR(
F16Coder::Read(br, &encoding->dct4x8multipliers[c])); if (std::abs(encoding->dct4x8multipliers[c]) < kAlmostZero) { return JXL_FAILURE("DCT4X8 multiplier is too small");
}
}
JXL_RETURN_IF_ERROR(DecodeDctParams(br, &encoding->dct_params)); break;
} case QuantEncoding::kQuantModeDCT4: { if (required_size != 1) return JXL_FAILURE("Invalid mode"); for (size_t c = 0; c < 3; c++) { for (size_t i = 0; i < 2; i++) {
JXL_RETURN_IF_ERROR(
F16Coder::Read(br, &encoding->dct4multipliers[c][i])); if (std::abs(encoding->dct4multipliers[c][i]) < kAlmostZero) { return JXL_FAILURE("DCT4 multiplier is too small");
}
}
}
JXL_RETURN_IF_ERROR(DecodeDctParams(br, &encoding->dct_params)); break;
} case QuantEncoding::kQuantModeAFV: { if (required_size != 1) return JXL_FAILURE("Invalid mode"); for (size_t c = 0; c < 3; c++) { for (size_t i = 0; i < 9; i++) {
JXL_RETURN_IF_ERROR(F16Coder::Read(br, &encoding->afv_weights[c][i]));
} for (size_t i = 0; i < 6; i++) {
encoding->afv_weights[c][i] *= 64;
}
}
JXL_RETURN_IF_ERROR(DecodeDctParams(br, &encoding->dct_params));
JXL_RETURN_IF_ERROR(DecodeDctParams(br, &encoding->dct_params_afv_4x4)); break;
} case QuantEncoding::kQuantModeDCT: {
JXL_RETURN_IF_ERROR(DecodeDctParams(br, &encoding->dct_params)); break;
} case QuantEncoding::kQuantModeRAW: { // Set mode early, to avoid mem-leak.
encoding->mode = QuantEncoding::kQuantModeRAW;
JXL_RETURN_IF_ERROR(ModularFrameDecoder::DecodeQuantTable(
memory_manager, required_size_x, required_size_y, br, encoding, idx,
modular_frame_decoder)); break;
} default: return JXL_FAILURE("Invalid quantization table encoding");
}
encoding->mode = static_cast<QuantEncoding::Mode>(mode); returntrue;
}
Status DequantMatrices::Decode(JxlMemoryManager* memory_manager, BitReader* br,
ModularFrameDecoder* modular_frame_decoder) {
size_t all_default = br->ReadBits(1);
size_t num_tables = all_default ? 0 : static_cast<size_t>(kNumQuantTables);
encodings_.clear();
encodings_.resize(kNumQuantTables, QuantEncoding::Library<0>()); for (size_t i = 0; i < num_tables; i++) {
JXL_RETURN_IF_ERROR(jxl::Decode(memory_manager, br, &encodings_[i],
required_size_x[i % kNumQuantTables],
required_size_y[i % kNumQuantTables], i,
modular_frame_decoder));
}
computed_mask_ = 0; returntrue;
}
Status DequantMatrices::DecodeDC(BitReader* br) { bool all_default = static_cast<bool>(br->ReadBits(1)); if (!br->AllReadsWithinBounds()) return JXL_FAILURE("EOS during DecodeDC"); if (!all_default) { for (size_t c = 0; c < 3; c++) {
JXL_RETURN_IF_ERROR(F16Coder::Read(br, &dc_quant_[c]));
dc_quant_[c] *= 1.0f / 128.0f; // Negative values and nearly zero are invalid values. if (dc_quant_[c] < kAlmostZero) { return JXL_FAILURE("Invalid dc_quant: coefficient is too small.");
}
inv_dc_quant_[c] = 1.0f / dc_quant_[c];
}
} returntrue;
}
DequantMatrices::DequantLibraryInternal DequantMatrices::LibraryInit() {
static_assert(kNumQuantTables == 17, "Update this function when adding new quantization kinds.");
static_assert(kNumPredefinedTables == 1, "Update this function when adding new quantization matrices to " "the library.");
// The library and the indices need to be kept in sync manually.
static_assert(0 == static_cast<uint8_t>(QuantTable::DCT), "Update the DequantLibrary array below.");
static_assert(1 == static_cast<uint8_t>(QuantTable::IDENTITY), "Update the DequantLibrary array below.");
static_assert(2 == static_cast<uint8_t>(QuantTable::DCT2X2), "Update the DequantLibrary array below.");
static_assert(3 == static_cast<uint8_t>(QuantTable::DCT4X4), "Update the DequantLibrary array below.");
static_assert(4 == static_cast<uint8_t>(QuantTable::DCT16X16), "Update the DequantLibrary array below.");
static_assert(5 == static_cast<uint8_t>(QuantTable::DCT32X32), "Update the DequantLibrary array below.");
static_assert(6 == static_cast<uint8_t>(QuantTable::DCT8X16), "Update the DequantLibrary array below.");
static_assert(7 == static_cast<uint8_t>(QuantTable::DCT8X32), "Update the DequantLibrary array below.");
static_assert(8 == static_cast<uint8_t>(QuantTable::DCT16X32), "Update the DequantLibrary array below.");
static_assert(9 == static_cast<uint8_t>(QuantTable::DCT4X8), "Update the DequantLibrary array below.");
static_assert(10 == static_cast<uint8_t>(QuantTable::AFV0), "Update the DequantLibrary array below.");
static_assert(11 == static_cast<uint8_t>(QuantTable::DCT64X64), "Update the DequantLibrary array below.");
static_assert(12 == static_cast<uint8_t>(QuantTable::DCT32X64), "Update the DequantLibrary array below.");
static_assert(13 == static_cast<uint8_t>(QuantTable::DCT128X128), "Update the DequantLibrary array below.");
static_assert(14 == static_cast<uint8_t>(QuantTable::DCT64X128), "Update the DequantLibrary array below.");
static_assert(15 == static_cast<uint8_t>(QuantTable::DCT256X256), "Update the DequantLibrary array below.");
static_assert(16 == static_cast<uint8_t>(QuantTable::DCT128X256), "Update the DequantLibrary array below."); return DequantMatrices::DequantLibraryInternal{{
DequantMatricesLibraryDef::DCT(),
DequantMatricesLibraryDef::IDENTITY(),
DequantMatricesLibraryDef::DCT2X2(),
DequantMatricesLibraryDef::DCT4X4(),
DequantMatricesLibraryDef::DCT16X16(),
DequantMatricesLibraryDef::DCT32X32(),
DequantMatricesLibraryDef::DCT8X16(),
DequantMatricesLibraryDef::DCT8X32(),
DequantMatricesLibraryDef::DCT16X32(),
DequantMatricesLibraryDef::DCT4X8(),
DequantMatricesLibraryDef::AFV0(),
DequantMatricesLibraryDef::DCT64X64(),
DequantMatricesLibraryDef::DCT32X64(), // Same default for large transforms (128+) as for 64x* transforms.
DequantMatricesLibraryDef::DCT128X128(),
DequantMatricesLibraryDef::DCT64X128(),
DequantMatricesLibraryDef::DCT256X256(),
DequantMatricesLibraryDef::DCT128X256(),
}};
}
const QuantEncoding* DequantMatrices::Library() { staticconst DequantMatrices::DequantLibraryInternal kDequantLibrary =
DequantMatrices::LibraryInit(); // Downcast the result to a const QuantEncoding* from QuantEncodingInternal* // since the subclass (QuantEncoding) doesn't add any new members and users // will need to upcast to QuantEncodingInternal to access the members of that // class. This allows to have kDequantLibrary as a constexpr value while still // allowing to create QuantEncoding::RAW() instances that use std::vector in // C++11. returnreinterpret_cast<const QuantEncoding*>(kDequantLibrary.data());
}
DequantMatrices::DequantMatrices() {
encodings_.resize(kNumQuantTables, QuantEncoding::Library<0>());
size_t pos = 0;
size_t offsets[kNumQuantTables * 3]; for (size_t i = 0; i < static_cast<size_t>(kNumQuantTables); i++) {
size_t num = required_size_x[i] * required_size_y[i] * kDCTBlockSize; for (size_t c = 0; c < 3; c++) {
offsets[3 * i + c] = pos + c * num;
}
pos += 3 * num;
} for (size_t i = 0; i < AcStrategy::kNumValidStrategies; i++) { for (size_t c = 0; c < 3; c++) {
table_offsets_[i * 3 + c] =
offsets[static_cast<size_t>(kAcStrategyToQuantTableMap[i]) * 3 + c];
}
}
}
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.