libwebp2: Upstream sync
Squashed commits:
6ef184b369a96cbf49ac7b46d973ac31daaac311 rework Quantizer::Config
6ca8d0e4fa7d1bdbdd16b526aac2af926bd16af7 Small Quantizer refactors.
6e977b6b4499d4315ee15b2fd0734d564b532163 Fix quantizer memory corruption.
238a52b64601f1168ab70c2f2276f4d04627a6da wp2: Remove YModePredictor predictor
56460010c1a736e611957e2fce238960575e2fd2 FrontMgr refactor
fc360e8638a56f2dce21193d60045ca9e9d2e9bc Fix cost estimations in WriteHeaders
3f7117244aa3137c96c0bfc0c64d17f8c7be9ee0 Send the effort parameter to the Quantizer.
Change-Id: I1e5605ace78c670c4d63ce657ff64eb19776bd70
Reviewed-on: https://chromium-review.googlesource.com/c/codecs/libwebp2/+/2643497
Reviewed-by: Pascal Massimino <skal@google.com>
Tested-by: Pascal Massimino <skal@google.com>
Verified-Ubuntu: Yannis Guyon <yguyon@google.com>
diff --git a/src/common/lossy/block.cc b/src/common/lossy/block.cc
index e9022c6..c73aed8 100644
--- a/src/common/lossy/block.cc
+++ b/src/common/lossy/block.cc
@@ -799,17 +799,12 @@
if (channel == kUChannel) pred_scores_[kVChannel] = pred_scores_[kUChannel];
}
-WP2Status CodedBlock::PredictorRate(
- const YModePredictor* const ymode_predictor, Channel channel,
- SymbolCounter* const counter, float* const rate) const {
+WP2Status CodedBlock::PredictorRate(Channel channel,
+ SymbolCounter* const counter,
+ float* const rate) const {
counter->Clear();
ANSEncCounter enc;
- if (channel == kYChannel || channel == kAChannel) {
- SyntaxWriter::WriteYAPredictors(*this, channel, ymode_predictor,
- /*update_ymodes=*/false, counter, &enc);
- } else {
- SyntaxWriter::WriteUVPredictors(*this, channel, counter, &enc);
- }
+ SyntaxWriter::WritePredictors(*this, channel, counter, &enc);
*rate = enc.GetCost();
return WP2_STATUS_OK;
}
@@ -840,8 +835,7 @@
WP2_CHECK_STATUS(ResidualRate(context, channel, num_channels,
counters->residuals(),
counters->residuals_aom(), res_rate));
- WP2_CHECK_STATUS(PredictorRate(is_uv ? nullptr : &context.ymodes(), channel,
- counters->predictor(), pred_rate));
+ WP2_CHECK_STATUS(PredictorRate(channel, counters->predictor(), pred_rate));
const float rate = *res_rate + *pred_rate + tf_rate;
*score =
diff --git a/src/common/lossy/block.h b/src/common/lossy/block.h
index e9e7c8a..7780e56 100644
--- a/src/common/lossy/block.h
+++ b/src/common/lossy/block.h
@@ -75,32 +75,25 @@
//------------------------------------------------------------------------------
// Context passed around and updated once we know the right parameters for each
-// block. Only contains AOM context for now.
+// block. Currently quite empty but can be removed or extended when needed.
class BlockContext {
public:
- // 'use_aom' defines the usage of AOM residuals. 'width' and 'height' are in
- // pixels.
- WP2Status Init(bool use_aom, uint32_t width, uint32_t height) {
+ // 'use_aom' defines the usage of AOM residuals.
+ WP2Status Init(bool use_aom) {
use_aom_ = use_aom;
- WP2_CHECK_STATUS(modes_.InitMap(width, height));
return WP2_STATUS_OK;
}
WP2Status CopyFrom(const BlockContext& other) {
use_aom_ = other.use_aom_;
- WP2_CHECK_STATUS(modes_.CopyFrom(other.modes_));
return WP2_STATUS_OK;
}
void Reset() {
- modes_.Reset();
}
bool use_aom() const { return use_aom_; }
- const YModePredictor& ymodes() const { return modes_; }
- YModePredictor& ymodes() { return modes_; }
private:
bool use_aom_ = false;
- YModePredictor modes_;
};
//------------------------------------------------------------------------------
@@ -467,8 +460,7 @@
// Returns an estimation of the number of bits necessary to encode the
// predictor modes.
- WP2Status PredictorRate(const YModePredictor* const ymode_predictor,
- Channel channel, SymbolCounter* const counter,
+ WP2Status PredictorRate(Channel channel, SymbolCounter* const counter,
float* const rate) const;
// Returns an estimation of the number of bits necessary to encode the
diff --git a/src/common/lossy/context.cc b/src/common/lossy/context.cc
index 07b7834..42189f1 100644
--- a/src/common/lossy/context.cc
+++ b/src/common/lossy/context.cc
@@ -297,58 +297,6 @@
}
//------------------------------------------------------------------------------
-// LargeModePredictor
-
-WP2Status YModePredictor::InitMap(uint32_t width, uint32_t) {
- const uint32_t map_width = SizeBlocks(width);
- WP2_CHECK_ALLOC_OK(map_.resize(map_width * kMapHeight));
- predictor_ctxt_.Init(&map_, map_width, kMapHeight);
- Reset();
- return WP2_STATUS_OK;
-}
-
-WP2Status YModePredictor::CopyFrom(const YModePredictor& other) {
- WP2_CHECK_ALLOC_OK(map_.copy_from(other.map_));
- const uint32_t map_width = (uint32_t)map_.size() / kMapHeight;
- assert(map_width * kMapHeight == other.map_.size());
- predictor_ctxt_.Init(&map_, map_width, kMapHeight);
- // Nothing else to copy in 'predictor_ctxt_' as it only points to 'map_'.
- return WP2_STATUS_OK;
-}
-
-void YModePredictor::Reset() { std::fill(map_.begin(), map_.end(), -1); }
-
-static uint32_t GetCluster(const ContextImpl<int8_t>& ctxt,
- const CodedBlock& cb) {
- const int above_mode = (cb.y() > 0) ? ctxt.Get(cb.x(), cb.y() - 1) : 0;
- const int left_mode = (cb.x() > 0) ? ctxt.Get(cb.x() - 1, cb.y()) : 0;
- return (above_mode == left_mode && above_mode >= 0)
- ? above_mode
- : (uint32_t)Predictor::ModeContext::kNum;
-}
-
-void YModePredictor::Write(const CodedBlock& cb, const Predictor& pred,
- bool do_update, ANSEncBase* const enc,
- SymbolManager* const sw) {
- const uint32_t cluster = GetCluster(predictor_ctxt_, cb);
- sw->Process(kSymbolModeY, cluster, pred.mode(), "predictor", enc);
- if (do_update) {
- const Predictor::ModeContext ctxt = pred.mode_context();
- predictor_ctxt_.Set(cb.blk(), (int)ctxt);
- }
-}
-
-uint32_t YModePredictor::Read(const CodedBlock& cb, const Predictors& preds,
- SymbolReader* const sr) {
- const uint32_t cluster = GetCluster(predictor_ctxt_, cb);
- const uint32_t mode = sr->Read(kSymbolModeY, cluster, "predictor", nullptr);
- const Predictor::ModeContext ctxt =
- preds.GetFirstWithMode(mode)->mode_context();
- predictor_ctxt_.Set(cb.blk(), (int)ctxt);
- return mode;
-}
-
-//------------------------------------------------------------------------------
// AlphaModePredictor
//------------------------------------------------------------------------------
diff --git a/src/common/lossy/context.h b/src/common/lossy/context.h
index 18a4388..074efd6 100644
--- a/src/common/lossy/context.h
+++ b/src/common/lossy/context.h
@@ -227,34 +227,6 @@
};
//------------------------------------------------------------------------------
-// Mode-predictor predictor (yes ...).
-
-class Predictor;
-class Predictors;
-// Predicts the predictor of a block, based on the predictor modes around that
-// block. The logic is different from AV1 where a CDF is chosen in a 2d table
-// based on the mode above and on the left. Here, if the above and left modes
-// are the same, we choose a CDF based on the mode, otherwise we choose the
-// generic CDF.
-class YModePredictor {
- public:
- YModePredictor() = default;
-
- // Will allocate the internal working map_[]. width and height in pixels.
- WP2Status InitMap(uint32_t width, uint32_t height);
- WP2Status CopyFrom(const YModePredictor& other);
- void Reset();
- void Write(const CodedBlock& cb, const Predictor& pred, bool do_update,
- ANSEncBase* const enc, SymbolManager* const sw);
- uint32_t Read(const CodedBlock& cb, const Predictors& preds,
- SymbolReader* const sr);
-
- private:
- Vector_s8 map_;
- ContextImpl<int8_t> predictor_ctxt_;
-};
-
-//------------------------------------------------------------------------------
// Alpha mode predictor.
class AlphaModePredictor {
diff --git a/src/common/lossy/predictor.cc b/src/common/lossy/predictor.cc
index 6eda268..aa97f00 100644
--- a/src/common/lossy/predictor.cc
+++ b/src/common/lossy/predictor.cc
@@ -196,7 +196,6 @@
public:
enum Type { kAll, kLeft, kTop };
explicit LargeDCPredictor(Type type) : type_(type) {}
- ModeContext mode_context() const override { return ModeContext::kDC; }
std::string GetName() const override {
const char* const kTypeStr[]{"all", "left", "top"};
@@ -228,10 +227,6 @@
public:
TMPredictor(int16_t min_value, int16_t max_value)
: min_value_(min_value), max_value_(max_value) {}
- ModeContext mode_context() const override {
- // Just like 135 degrees.
- return ModeContext::kLeft;
- }
std::string GetName() const override { return "TM predictor"; }
void Draw(const WP2::Rectangle& rect,
@@ -262,15 +257,6 @@
kNumSmoothType
};
explicit SmoothPredictor(SmoothType type) : type_(type) {}
- ModeContext mode_context() const override {
- if (type_ == SmoothType::k2DSmooth) {
- return ModeContext::kDC;
- } else if (type_ == SmoothType::kVerticalSmooth) {
- return ModeContext::kVertical;
- } else {
- return ModeContext::kHorizontal;
- }
- }
std::string GetName() const override {
const char* const kTypeStr[]{"2D", "vertical", "horizontal"};
@@ -336,24 +322,6 @@
context_type_ = GetContextType(angle_idx_);
}
- ModeContext mode_context() const override {
- if (type_ == Type::D23_PRED || type_ == Type::D45_PRED ||
- type_ == Type::D67_PRED) {
- return ModeContext::kTopRight;
- } else if (type_ == Type::V_PRED) {
- return ModeContext::kVertical;
- } else if (type_ == Type::D113_PRED || type_ == Type::D135_PRED ||
- type_ == Type::D157_PRED || type_ == Type::D203_PRED ||
- type_ == Type::D225_PRED) {
- return ModeContext::kLeft;
- } else if (type_ == Type::H_PRED) {
- return ModeContext::kHorizontal;
- } else {
- assert(false);
- }
- return ModeContext::kDC;
- }
-
// Returns the angle index for precalculated angles.
// Index goes from 0 (12.86 degrees) to 69 (234.64 degrees).
static uint8_t AngleIdx(Type type, Channel channel, int16_t angle_step) {
@@ -452,10 +420,6 @@
: strength_(strength), min_value_(min_value), max_value_(max_value) {
PrecomputeLargeWeightTable(strength_, table_);
}
- ModeContext mode_context() const override {
- // TODO(vrabaud) find the right one.
- return ModeContext::kDC;
- }
std::string GetName() const override {
std::string name = "fuse predictor (strength: ";
@@ -489,11 +453,6 @@
public:
GradientPredictor(int16_t min_value, int16_t max_value)
: min_value_(min_value), max_value_(max_value) {}
- ModeContext mode_context() const override {
- // TODO(vrabaud) find the right one.
- // Just like 135 degrees.
- return ModeContext::kLeft;
- }
std::string GetName() const override { return "gradient predictor"; }
void Draw(const WP2::Rectangle& rect,
diff --git a/src/common/lossy/predictor.h b/src/common/lossy/predictor.h
index 16f021e..e08bb22 100644
--- a/src/common/lossy/predictor.h
+++ b/src/common/lossy/predictor.h
@@ -58,18 +58,6 @@
// heuristics and local context information.
class Predictor : public WP2Allocable {
public:
- // Context of the prediction: each predictor can belong to a context (mainly
- // horizontal, mainly vertical ...). AV1 defines the mapping between the
- // predictor and a mode in Intra_Mode_Context.
- enum class ModeContext {
- kDC,
- kVertical,
- kHorizontal,
- kTopRight,
- kLeft, // for left angle predictors that are not horizontal.
- kNum
- };
-
virtual ~Predictor() = default;
// Predicts values for the given block, on channel 'channel', for the
@@ -118,7 +106,6 @@
// predictors.
void SetMode(uint32_t mode) { mode_ = mode; }
virtual uint32_t mode() const { return mode_; }
- virtual ModeContext mode_context() const { return ModeContext::kNum; }
// Debugging methods.
virtual std::string GetName() const = 0;
diff --git a/src/common/symbols.cc b/src/common/symbols.cc
index a85ceb3..c7a53ca 100644
--- a/src/common/symbols.cc
+++ b/src/common/symbols.cc
@@ -214,10 +214,8 @@
uint32_t quality_hint, bool use_aom_coeffs) {
const uint32_t num_channels = (has_alpha ? 4 : 3);
- // kNum is used as an escape code when the upper/left mode do not match.
SetInfo(kSymbolModeY, /*min=*/0, /*max=*/kYPredModeNum - 1,
- (uint32_t)Predictor::ModeContext::kNum + 1,
- StorageMethod::kAdaptiveSym);
+ /*num_clusters=*/1, StorageMethod::kAdaptiveSym);
SetInfo(kSymbolModeUV, /*min=*/0, /*max=*/kUVPredModeNum - 1,
/*num_clusters=*/1, StorageMethod::kAdaptiveWithAutoSpeed);
SetInfo(kSymbolSegmentId, /*min=*/0, /*max=*/num_segments - 1,
diff --git a/src/common/symbols.h b/src/common/symbols.h
index d3c7367..e84f103 100644
--- a/src/common/symbols.h
+++ b/src/common/symbols.h
@@ -322,11 +322,6 @@
class SymbolIO {
public:
virtual ~SymbolIO() = default;
- // Sets basic information about symbols.
- WP2Status Init(const SymbolsInfo& symbols_info) {
- WP2_CHECK_STATUS(symbols_info_.CopyFrom(symbols_info));
- return WP2_STATUS_OK;
- }
// Allocates data after ranges/cluster sizes have been specified.
virtual WP2Status Allocate() {
@@ -405,6 +400,12 @@
Param param;
EXTRA extra;
};
+ // Sets basic information about symbols.
+ WP2Status Init(const SymbolsInfo& symbols_info) {
+ WP2_CHECK_STATUS(symbols_info_.CopyFrom(symbols_info));
+ return WP2_STATUS_OK;
+ }
+
// Gets the statistics for symbol 'sym' in cluster 'cluster'.
inline Stat* GetStats(uint32_t sym, uint32_t cluster) {
assert(sym < symbols_info_.Size() &&
diff --git a/src/dec/syntax_dec.cc b/src/dec/syntax_dec.cc
index 280ed06..bd35b5f 100644
--- a/src/dec/syntax_dec.cc
+++ b/src/dec/syntax_dec.cc
@@ -47,14 +47,13 @@
ANSDebugPrefix prefix(dec_, "GlobalHeader");
- use_aom_coeffs_ = dec_->ReadBool("use_aom_coeffs");
- WP2_CHECK_STATUS(context_.Init(use_aom_coeffs_, width_, height_));
- residual_reader_.Init(use_aom_coeffs_);
+ WP2_CHECK_STATUS(context_.Init(dec_->ReadBool("use_aom_coeffs")));
+ residual_reader_.Init(context_.use_aom());
WP2_CHECK_STATUS(symbols_info_.InitLossy(
(uint32_t)gparams_->segments_.size(), gparams.partition_set_,
gparams_->maybe_use_lossy_alpha_, features.quality_hint,
- use_aom_coeffs_));
+ context_.use_aom()));
const uint32_t num_channels = (gparams_->maybe_use_lossy_alpha_ ? 4 : 3);
for (Channel c : {kYChannel, kUChannel, kVChannel, kAChannel}) {
if (c == kAChannel && !gparams_->maybe_use_lossy_alpha_) continue;
@@ -157,20 +156,15 @@
ANSDebugPrefix prefix(dec_, "pred_modes");
cb->y_context_is_constant_ = cb->ContextIsConstant(kYChannel);
for (Channel channel : {kYChannel, kAChannel}) {
- ANSDebugPrefix prefix2(dec_, (channel == kYChannel) ? "y" : "a");
if (channel == kAChannel && !cb->HasLossyAlpha()) continue;
if (channel == kYChannel && cb->y_context_is_constant_) {
cb->SetLumaUniformPredictor(gparams_->y_preds_);
} else {
CodedBlock::CodingParams* const params = cb->GetCodingParams(channel);
const Predictors& preds = gparams_->predictors(channel);
- uint32_t mode;
- if (channel == kYChannel) {
- mode = context_.ymodes().Read(*cb, preds, &sr_);
- } else {
- assert(channel == kAChannel);
- mode = sr_.Read(kSymbolModeA, "pred");
- }
+ const uint32_t mode = (channel == kYChannel)
+ ? sr_.Read(kSymbolModeY, "y")
+ : sr_.Read(kSymbolModeA, "a");
preds.GetFirstWithMode(mode)->ReadParams(cb, channel, &sr_, dec_);
params->pred = preds.GetWithMode(mode, params->pred_sub_mode);
}
@@ -287,7 +281,7 @@
dec_->PopBitTracesCustomPrefix("transforms");
// Signal the method with which coeffs were encoded.
- if (!use_aom_coeffs_) {
+ if (!context_.use_aom()) {
ANSDebugPrefix prefix(dec_, "coeff_method");
const Segment& segment = gparams_->segments_[cb->id_];
WP2_CHECK_STATUS(segment.ReadEncodingMethods(&sr_, cb));
diff --git a/src/dec/wp2_dec_i.h b/src/dec/wp2_dec_i.h
index c9c7b70..21a1687 100644
--- a/src/dec/wp2_dec_i.h
+++ b/src/dec/wp2_dec_i.h
@@ -269,7 +269,6 @@
BlockContext context_;
uint32_t width_;
uint32_t height_;
- bool use_aom_coeffs_;
public:
// Visual debug: stores bit cost for a block
diff --git a/src/enc/lossless/backward_references_enc.cc b/src/enc/lossless/backward_references_enc.cc
index ba843ec..28169e4 100644
--- a/src/enc/lossless/backward_references_enc.cc
+++ b/src/enc/lossless/backward_references_enc.cc
@@ -739,10 +739,10 @@
// Get the header cost in bits.
WP2::ANSEncCounter enc_counter;
WP2::SymbolWriter symbol_writer;
- WP2_CHECK_STATUS(symbol_writer.Init(info));
+ WP2_CHECK_STATUS(symbol_writer.Init(info, effort));
WP2_CHECK_STATUS(symbol_writer.Allocate());
WP2::ANSDictionaries dicts;
- WP2_CHECK_STATUS(WriteHeaders(symbol_recorder, info, num_pixels,
+ WP2_CHECK_STATUS(WriteHeaders(symbol_recorder, info, num_pixels, effort,
&enc_counter, &dicts, &symbol_writer));
const float cost_header = enc_counter.GetCost();
@@ -816,7 +816,7 @@
// Gets the overall cost of storing the refs: symbol headers and pixels.
static WP2Status GetStorageCost(uint32_t width, const BackwardRefs& refs,
const LosslessSymbolsInfo& symbols_info,
- uint32_t num_pixels,
+ uint32_t num_pixels, int effort,
float* const cost) {
// Get the symbols stats.
WP2::SymbolRecorder recorder;
@@ -828,7 +828,7 @@
WP2::ANSEncCounter enc_counter;
WP2::ANSDictionaries dicts;
WP2::SymbolWriter symbol_writer;
- WP2_CHECK_STATUS(WriteHeaders(recorder, symbols_info, num_pixels,
+ WP2_CHECK_STATUS(WriteHeaders(recorder, symbols_info, num_pixels, effort,
&enc_counter, &dicts, &symbol_writer));
WP2_CHECK_STATUS(StorePixels(width, refs, &enc_counter, &symbol_writer));
*cost = enc_counter.GetCost();
@@ -910,7 +910,7 @@
float bit_cost;
WP2_CHECK_STATUS(GetStorageCost(width, *refs_tmp, symbols_info_tmp,
- num_pixels, &bit_cost));
+ num_pixels, effort, &bit_cost));
// Improve on simple LZ77 but only for high effort (TraceBackwards is
// costly).
@@ -927,7 +927,7 @@
assert(refs_tmp_trace->IsValid(num_pixels));
float bit_cost_trace;
WP2_CHECK_STATUS(GetStorageCost(width, *refs_tmp_trace,
- symbols_info_tmp, num_pixels,
+ symbols_info_tmp, num_pixels, effort,
&bit_cost_trace));
if (bit_cost_trace < bit_cost) {
bit_cost = bit_cost_trace;
diff --git a/src/enc/lossless/group4_enc.cc b/src/enc/lossless/group4_enc.cc
index 3f515c1..f74fd02 100644
--- a/src/enc/lossless/group4_enc.cc
+++ b/src/enc/lossless/group4_enc.cc
@@ -230,7 +230,7 @@
WP2Status Group4Encode(const int16_t* const argb, uint32_t width,
uint32_t height, uint32_t num_colors,
- bool use_move_to_front,
+ bool use_move_to_front, int effort,
const WP2::ProgressRange& progress,
WP2::ANSEncBase* const enc,
EncodeInfo* const encode_info) {
@@ -253,7 +253,7 @@
// Write the headers.
WP2::SymbolWriter sw;
- WP2_CHECK_STATUS(sw.Init(info));
+ WP2_CHECK_STATUS(sw.Init(info, effort));
WP2_CHECK_STATUS(sw.Allocate());
enc->AddDebugPrefix("GlobalHeader");
diff --git a/src/enc/lossless/losslessi_enc.cc b/src/enc/lossless/losslessi_enc.cc
index 7ee81bd..40521ae 100644
--- a/src/enc/lossless/losslessi_enc.cc
+++ b/src/enc/lossless/losslessi_enc.cc
@@ -195,11 +195,12 @@
// in the A,R,B channels.
WP2Status WriteHeaders(const WP2::SymbolRecorder& recorder,
const LosslessSymbolsInfo& symbols_info,
- uint32_t num_pixels, WP2::ANSEncBase* const enc,
+ uint32_t num_pixels, int effort,
+ WP2::ANSEncBase* const enc,
WP2::ANSDictionaries* const dicts,
WP2::SymbolWriter* const sw) {
WP2::ANSDebugPrefix prefix(enc, "symbols");
- WP2_CHECK_STATUS(sw->Init(symbols_info));
+ WP2_CHECK_STATUS(sw->Init(symbols_info, effort));
WP2_CHECK_STATUS(sw->Allocate());
// Iterate over all histograms and get the aggregate number of codes used.
@@ -257,8 +258,8 @@
WP2_CHECK_STATUS(StorePixels(width, *refs, &noop, &recorder));
// Store headers.
- WP2_CHECK_STATUS(WriteHeaders(recorder, symbols_info_new, width * height, enc,
- dicts, &sw));
+ WP2_CHECK_STATUS(WriteHeaders(recorder, symbols_info_new, width * height,
+ effort, enc, dicts, &sw));
// Store actual literals.
WP2_CHECK_STATUS(StorePixels(width, height, /*histo_bits=*/0, *refs, progress,
@@ -386,8 +387,8 @@
&enc_noop, &recorder));
// Store symbol headers.
- WP2_CHECK_STATUS(
- WriteHeaders(recorder, symbols_info, num_pixels, enc, dicts, &sw));
+ WP2_CHECK_STATUS(WriteHeaders(recorder, symbols_info, num_pixels, effort,
+ enc, dicts, &sw));
WP2_CHECK_STATUS(header_progress.AdvanceBy(1.));
}
@@ -803,8 +804,8 @@
if (use_group4) {
WP2_CHECK_STATUS(
Group4Encode(encoder->argb_, width, height, encoder->palette_.Size(),
- config->group4_use_move_to_front, encode_progress, &enc,
- ¤t_encode_info));
+ config->group4_use_move_to_front, effort,
+ encode_progress, &enc, ¤t_encode_info));
} else {
// If using a color cache, do not have it bigger than the number of
// colors.
diff --git a/src/enc/lossless/losslessi_enc.h b/src/enc/lossless/losslessi_enc.h
index 37bd8f2..794039e 100644
--- a/src/enc/lossless/losslessi_enc.h
+++ b/src/enc/lossless/losslessi_enc.h
@@ -134,7 +134,8 @@
// info.
WP2Status WriteHeaders(const WP2::SymbolRecorder& recorder,
const LosslessSymbolsInfo& symbols_info,
- uint32_t num_pixels, WP2::ANSEncBase* const enc,
+ uint32_t num_pixels, int effort,
+ WP2::ANSEncBase* const enc,
WP2::ANSDictionaries* const dicts,
WP2::SymbolWriter* const sw);
@@ -180,7 +181,7 @@
WP2Status Group4Encode(const int16_t* const argb, uint32_t width,
uint32_t height, uint32_t num_colors,
- bool use_move_to_front,
+ bool use_move_to_front, int effort,
const WP2::ProgressRange& progress,
WP2::ANSEncBase* const enc,
EncodeInfo* const encode_info);
diff --git a/src/enc/lossy_enc.cc b/src/enc/lossy_enc.cc
index 8434a9a..33e7ca3 100644
--- a/src/enc/lossy_enc.cc
+++ b/src/enc/lossy_enc.cc
@@ -137,24 +137,25 @@
const CSPTransform& transf = gparams.transf_;
// First, extract partitioning.
- Vector<CodedBlock> cblocks;
+ VectorNoCtor<Block> blocks;
+ WP2_CHECK_ALLOC_OK(blocks.resize(forced_partition.size()));
+ std::copy(forced_partition.begin(), forced_partition.end(), blocks.begin());
+ WP2_CHECK_STATUS(ExtractBlockPartition(*config_, gparams, yuv_buffer,
+ tile_rect, partitioning_progress,
+ &blocks));
FrontMgrDefault mgr;
WP2_CHECK_STATUS(mgr.Init(config_->partition_set, config_->partition_snapping,
padded_rect.width, padded_rect.height));
- WP2_CHECK_ALLOC_OK(mgr.Blocks().resize(forced_partition.size()));
- std::copy(forced_partition.begin(), forced_partition.end(),
- mgr.Blocks().begin());
- WP2_CHECK_STATUS(ExtractBlockPartition(*config_, gparams, yuv_buffer,
- tile_rect, partitioning_progress,
- &mgr.Blocks()));
- WP2_CHECK_STATUS(mgr.Sort());
+
+ Vector_u16 size_order_indices;
+ WP2_CHECK_STATUS(mgr.Sort(blocks, size_order_indices));
// process all blocks
- WP2_CHECK_ALLOC_OK(cblocks.resize(mgr.Blocks().size()));
// Setup the top-level coding info for each cblock
- mgr.Clear();
- for (uint32_t i = 0; i < mgr.Blocks().size(); ++i) {
- const auto& blk = mgr.Blocks()[i];
+ Vector<CodedBlock> cblocks;
+ WP2_CHECK_ALLOC_OK(cblocks.resize(blocks.size()));
+ for (uint32_t i = 0; i < blocks.size(); ++i) {
+ const auto& blk = blocks[i];
CodedBlock& cb = cblocks[i];
cb.SetRange(transf.GetYUVMin(), transf.GetYUVMax());
cb.SetDim(blk, mgr);
@@ -349,8 +350,8 @@
// Sizes might be written in a different order than the blocks, hence a
// separate recording: we need to follow the SizeIndices() order.
mgr.Clear();
- for (uint16_t ind : mgr.SizeIndices()) {
- const auto& block = mgr.Blocks()[ind];
+ for (uint16_t ind : size_order_indices) {
+ const auto& block = blocks[ind];
WP2_CHECK_STATUS(writer.RecordSize(mgr, block.dim()));
Block block_tmp;
WP2_CHECK_ALLOC_OK(mgr.UseSize(block.dim(), ind, &block_tmp));
@@ -368,7 +369,7 @@
WP2_CHECK_STATUS(writer.WriteHeader(enc));
// Write coded blocks
- WP2_CHECK_STATUS(writer.WriteBlocks(cblocks, &mgr, enc));
+ WP2_CHECK_STATUS(writer.WriteBlocks(cblocks, size_order_indices, &mgr, enc));
WP2_CHECK_STATUS(write_progress.AdvanceBy(1.));
#if !defined(WP2_REDUCE_BINARY_SIZE)
diff --git a/src/enc/partitioning/partition_score_func_area.cc b/src/enc/partitioning/partition_score_func_area.cc
index c330a80..2a7fcd8 100644
--- a/src/enc/partitioning/partition_score_func_area.cc
+++ b/src/enc/partitioning/partition_score_func_area.cc
@@ -95,7 +95,7 @@
WP2_CHECK_STATUS(syntax_writer_.SetInitialSegmentIds());
WP2_CHECK_STATUS(syntax_writer_.InitPass());
- WP2_CHECK_STATUS(context_.Init(use_aom_coeffs, yuv.Y.w_, yuv.Y.h_));
+ WP2_CHECK_STATUS(context_.Init(use_aom_coeffs));
if (DCDiffusionMap::GetDiffusion(config_->error_diffusion) > 0) {
WP2_CHECK_STATUS(dc_error_u_.Init(tile_rect_.width));
diff --git a/src/enc/partitioning/partition_score_func_block.cc b/src/enc/partitioning/partition_score_func_block.cc
index c6aca7d..794a45b 100644
--- a/src/enc/partitioning/partition_score_func_block.cc
+++ b/src/enc/partitioning/partition_score_func_block.cc
@@ -70,7 +70,7 @@
}
// Initialize the cache.
- WP2_CHECK_STATUS(context_.Init(use_aom_coeffs, yuv.Y.w_, yuv.Y.h_));
+ WP2_CHECK_STATUS(context_.Init(use_aom_coeffs));
WP2_CHECK_STATUS(progress.AdvanceBy(0.5));
return WP2_STATUS_OK;
}
diff --git a/src/enc/symbols_enc.cc b/src/enc/symbols_enc.cc
index 68da9b6..0a5e5e7 100644
--- a/src/enc/symbols_enc.cc
+++ b/src/enc/symbols_enc.cc
@@ -482,6 +482,7 @@
// No need to copy Quantizer instances. They only contain data members to
// avoid reallocations. TODO(yguyon): Check if more could be skipped
WP2_CHECK_ALLOC_OK(stats_buffer_.copy_from(other.stats_buffer_));
+ effort_ = other.effort_;
return WP2_STATUS_OK;
}
@@ -836,15 +837,15 @@
}
// Quantize the histogram to get the cost of using a dictionary.
quantizer_golomb_.Quantize(histogram_golomb_.data(), mapping_golomb_.data(),
- size_golomb, range_golomb, max_nnz,
- /*effort=*/9, config_golomb);
+ size_golomb, range_golomb, max_nnz, effort_,
+ config_golomb);
(*config_golomb)->param.golomb_size = size_golomb;
(*config_golomb)->param.golomb_prefix_size = prefix_size;
*cost += (*config_golomb)->cost;
// Do not use Golomb if there is only one value for now.
const uint32_t nnz_range_golomb = std::min(max_nnz, range_golomb);
// Add the prefix_size and size cost.
- *cost += 1.f + WP2Log2(nnz_range_golomb - 1);
+ *cost += 1.f + WP2Log2(nnz_range_golomb - 2);
}
WP2Status SymbolWriter::WriteHeader(uint32_t sym, uint32_t cluster,
@@ -1041,9 +1042,9 @@
if (size < ANS_MAX_SYMBOLS) {
// Quantize the histogram to get the cost of using a dictionary.
quantizer_.Quantize(histogram_.data(), mapping_.data(), size, range,
- max_nnz, /*effort=*/9, &config);
+ max_nnz, effort_, &config);
cost_dict = config->cost;
- cost_dict += WP2Log2(nnz_range); // Add the size cost.
+ cost_dict += WP2Log2(nnz_range - 2); // Add the size cost.
} else {
cost_dict = std::numeric_limits<float>::max();
}
diff --git a/src/enc/symbols_enc.h b/src/enc/symbols_enc.h
index bf6571e..92edc15 100644
--- a/src/enc/symbols_enc.h
+++ b/src/enc/symbols_enc.h
@@ -215,6 +215,13 @@
public SymbolIO<SymbolWriterStatExtra>,
public WP2Allocable {
public:
+ // Sets basic information about symbols.
+ WP2Status Init(const SymbolsInfo& symbols_info, int effort) {
+ WP2_CHECK_STATUS(SymbolIO<SymbolWriterStatExtra>::Init(symbols_info));
+ effort_ = effort;
+ return WP2_STATUS_OK;
+ }
+
const SymbolsInfo& symbols_info() const override { return symbols_info_; }
// Allocates memory. Should be called after calling SymbolIO::Init().
@@ -313,6 +320,7 @@
Quantizer quantizer_;
Quantizer quantizer_golomb_;
VectorNoCtor<OptimizeArrayStorageStat> stats_buffer_;
+ int effort_;
};
} // namespace WP2
diff --git a/src/enc/syntax_enc.cc b/src/enc/syntax_enc.cc
index ebb77b8..901926b 100644
--- a/src/enc/syntax_enc.cc
+++ b/src/enc/syntax_enc.cc
@@ -41,16 +41,17 @@
tile_rect_ = tile_rect;
gparams_ = &gparams;
assert(gparams_->IsOk());
- use_aom_coeffs_ = use_aom_coeffs;
chroma_subsampling_ = chroma_subsampling;
num_blocks_ = num_blocks;
// Number of transforms is unknown yet, use a higher bound.
num_transforms_ = std::min(
num_blocks * 4, SizeBlocks(yuv.GetWidth()) * SizeBlocks(yuv.GetHeight()));
+ // Deal with context.
+ WP2_CHECK_STATUS(context_.Init(use_aom_coeffs));
- WP2_CHECK_STATUS(
- residual_writer_.Init(use_aom_coeffs_, gparams_->maybe_use_lossy_alpha_));
+ WP2_CHECK_STATUS(residual_writer_.Init(context_.use_aom(),
+ gparams_->maybe_use_lossy_alpha_));
const uint32_t num_segments =
std::min((uint32_t)gparams_->segments_.size(),
@@ -60,9 +61,6 @@
// Deal with segment ids.
WP2_CHECK_STATUS(segment_ids_.InitWrite(
num_segments, gparams_->explicit_segment_ids_, tile_rect.width));
- // Deal with context.
- WP2_CHECK_STATUS(
- context_.Init(use_aom_coeffs_, tile_rect.width, tile_rect.height));
if (gparams_->has_alpha_) {
WP2_CHECK_STATUS(alpha_writer_.Init(*config_, gparams, context_, yuv,
@@ -97,7 +95,6 @@
tile_rect_ = other.tile_rect_;
chroma_subsampling_ = other.chroma_subsampling_;
gparams_ = other.gparams_;
- use_aom_coeffs_ = other.use_aom_coeffs_;
WP2_CHECK_STATUS(segment_ids_.CopyFrom(other.segment_ids_));
WP2_CHECK_STATUS(
@@ -115,7 +112,7 @@
WP2_CHECK_STATUS(symbols_info.InitLossy(
gparams_->segments_.size(), gparams_->partition_set_,
gparams_->maybe_use_lossy_alpha_, GetQualityHint(config_->quality),
- use_aom_coeffs_));
+ context_.use_aom()));
symbols_info.SetMinMax(kSymbolModeY, /*min=*/0,
/*max=*/gparams_->y_preds_.GetMaxMode());
if (gparams_->maybe_use_lossy_alpha_) {
@@ -133,7 +130,7 @@
}
symbols_info.SetClusters(kSymbolDC, symbols_info.NumClusters(kSymbolDC));
- WP2_CHECK_STATUS(symbol_writer_.Init(symbols_info));
+ WP2_CHECK_STATUS(symbol_writer_.Init(symbols_info, config_->effort));
WP2_CHECK_STATUS(symbol_writer_.Allocate());
if (pass_number_ == 0) {
WP2_CHECK_STATUS(symbol_recorder_.Allocate(
@@ -160,7 +157,7 @@
// TODO(skal): differential-write of gparams_
- enc->PutBool(use_aom_coeffs_, "use_aom_coeffs");
+ enc->PutBool(context_.use_aom(), "use_aom_coeffs");
// Write dictionaries.
PutLargeRange(num_blocks_, min_num_blocks, max_num_blocks, enc, "num_blocks");
@@ -246,7 +243,6 @@
}
void SyntaxWriter::WriteBlockBeforeCoeffs(const CodedBlock& cb,
- bool update_ymodes,
SymbolManager* const sm,
ANSEncBase* const enc) {
segment_ids_.WriteId(cb, sm, enc);
@@ -259,12 +255,7 @@
for (Channel channel : {kYChannel, kAChannel, kUChannel, kVChannel}) {
if (channel == kAChannel && !cb.HasLossyAlpha()) continue;
- if (channel == kYChannel || channel == kAChannel) {
- WriteYAPredictors(cb, channel, &context_.ymodes(), update_ymodes, sm,
- enc);
- } else {
- WriteUVPredictors(cb, channel, sm, enc);
- }
+ WritePredictors(cb, channel, sm, enc);
}
if (chroma_subsampling_ == ChromaSubsampling::kSingleBlock ||
@@ -279,7 +270,7 @@
WriteTransform(cb, channel, sm, enc);
}
- if (!use_aom_coeffs_) {
+ if (!context_.use_aom()) {
ANSDebugPrefix prefix(enc, "coeff_method");
gparams_->segments_[cb.id_].StoreEncodingMethods(cb, sm, enc);
}
@@ -292,32 +283,19 @@
}
}
-void SyntaxWriter::WriteYAPredictors(
- const CodedBlock& cb, Channel channel,
- const YModePredictor* const ymode_predictor, bool update_ymodes,
- SymbolManager* const sm, ANSEncBase* const enc) {
+void SyntaxWriter::WritePredictors(const CodedBlock& cb, Channel channel,
+ SymbolManager* const sm,
+ ANSEncBase* const enc) {
ANSDebugPrefix prefix(enc, "pred_modes");
const CodedBlock::CodingParams& params = cb.GetCodingParams(channel);
- ANSDebugPrefix prefix2(enc, (channel == kYChannel) ? "y" : "a");
- if (channel == kYChannel && cb.y_context_is_constant_) return;
if (channel == kYChannel) {
- assert(ymode_predictor != nullptr);
- const_cast<YModePredictor*>(ymode_predictor)
- ->Write(cb, *params.pred, update_ymodes, enc, sm);
- } else {
- assert(channel == kAChannel);
- sm->Process(kSymbolModeA, params.pred->mode(), "pred", enc);
- }
- params.pred->WriteParams(cb, channel, sm, enc);
-}
-
-void SyntaxWriter::WriteUVPredictors(const CodedBlock& cb, Channel channel,
- SymbolManager* const sm,
- ANSEncBase* const enc) {
- ANSDebugPrefix prefix(enc, "pred_modes");
- const CodedBlock::CodingParams& params = cb.GetCodingParams(channel);
- if (channel == kUChannel) {
+ if (cb.y_context_is_constant_) return;
+ sm->Process(kSymbolModeY, params.pred->mode(), "y", enc);
+ } else if (channel == kUChannel) {
sm->Process(kSymbolModeUV, params.pred->mode(), "uv", enc);
+ // kVChannel is not written as it is the same as kUChannel.
+ } else if (channel == kAChannel) {
+ sm->Process(kSymbolModeA, params.pred->mode(), "a", enc);
}
params.pred->WriteParams(cb, channel, sm, enc);
}
@@ -373,19 +351,21 @@
void SyntaxWriter::RecordBlockHeader(const CodedBlock& cb) {
ANSEncNoop enc;
- WriteBlockBeforeCoeffs(cb, /*update_ymodes=*/true, &symbol_recorder_, &enc);
+ WriteBlockBeforeCoeffs(cb, &symbol_recorder_, &enc);
}
WP2Status SyntaxWriter::WriteBlocks(const Vector<CodedBlock>& cblocks,
+ const Vector_u16& size_order_indices,
FrontMgrNxNBase* const mgr,
ANSEnc* const enc) {
assert(cblocks.size() == num_blocks_);
+ assert(size_order_indices.size() == num_blocks_);
// Note: we could call segment_ids_.InitMap(bw, bh) again here.
mgr->Clear();
- WP2_CHECK_STATUS(
- residual_writer_.Init(use_aom_coeffs_, gparams_->maybe_use_lossy_alpha_));
+ WP2_CHECK_STATUS(residual_writer_.Init(context_.use_aom(),
+ gparams_->maybe_use_lossy_alpha_));
context_.Reset();
- for (uint16_t ind : mgr->SizeIndices()) {
+ for (uint16_t ind : size_order_indices) {
{
ANSDebugPrefix prefix(enc, "BlockHeader");
const CodedBlock& cb = cblocks[ind];
@@ -411,7 +391,7 @@
for (auto c : {kYChannel, kUChannel, kVChannel, kAChannel}) {
if (c == kAChannel && !cb->HasLossyAlpha()) continue;
for (uint32_t tf_i = 0; tf_i < cb->GetNumTransforms(c); ++tf_i) {
- if (use_aom_coeffs_) {
+ if (context_.use_aom()) {
ResidualWriter::SetGeometry(cb->num_coeffs_[c][tf_i],
&cb->method_[c][tf_i]);
} else {
@@ -499,7 +479,7 @@
ANSEnc* const enc) {
{
ANSDebugPrefix prefix(enc, "BlockHeader");
- WriteBlockBeforeCoeffs(cb, /*update_ymodes=*/true, &symbol_writer_, enc);
+ WriteBlockBeforeCoeffs(cb, &symbol_writer_, enc);
}
float previous_cost;
diff --git a/src/enc/wp2_enc_i.h b/src/enc/wp2_enc_i.h
index e6deab6..ab8297d 100644
--- a/src/enc/wp2_enc_i.h
+++ b/src/enc/wp2_enc_i.h
@@ -322,15 +322,11 @@
// Writes the headers (frozen dictionaries, etc.).
WP2Status WriteHeader(ANSEncBase* const enc);
// These write the block header (segment id, preds, etc.).
- void WriteBlockBeforeCoeffs(const CodedBlock& cb, bool update_ymodes,
- SymbolManager* const sm, ANSEncBase* const enc);
+ void WriteBlockBeforeCoeffs(const CodedBlock& cb, SymbolManager* const sm,
+ ANSEncBase* const enc);
// Writes the predictors used by the given block for the given channel.
- static void WriteYAPredictors(const CodedBlock& cb, Channel channel,
- const YModePredictor* const ymode_predictor,
- bool update_ymodes, SymbolManager* const sm,
- ANSEncBase* const enc);
- static void WriteUVPredictors(const CodedBlock& cb, Channel channel,
- SymbolManager* const sm, ANSEncBase* const enc);
+ static void WritePredictors(const CodedBlock& cb, Channel channel,
+ SymbolManager* const sm, ANSEncBase* const enc);
// Writes whether the block is split into smaller square transforms.
static void WriteSplitTransform(const CodedBlock& cb, Channel channel,
SymbolManager* const sm,
@@ -342,7 +338,11 @@
static void WriteTransform(const CodedBlock& cb, Channel channel,
SymbolManager* const sm, ANSEncBase* const enc);
+ // Writes all blocks to 'enc'. 'size_order_indices' should be the same size
+ // as 'cblocks', and contain the indices of a permutation of 'cblocks' that
+ // puts it in size order (order in which block sizes are written).
WP2Status WriteBlocks(const Vector<CodedBlock>& cblocks,
+ const Vector_u16& size_order_indices,
FrontMgrNxNBase* const mgr, ANSEnc* const enc);
SymbolWriter* symbol_writer() { return &symbol_writer_; }
@@ -388,7 +388,6 @@
ChromaSubsampling chroma_subsampling_;
const GlobalParams* gparams_;
- bool use_aom_coeffs_;
SegmentIdPredictor segment_ids_;
BlockContext context_;
diff --git a/src/utils/front_mgr.cc b/src/utils/front_mgr.cc
index 82d786e..b41182e 100644
--- a/src/utils/front_mgr.cc
+++ b/src/utils/front_mgr.cc
@@ -197,8 +197,6 @@
snapped_ = other.snapped_;
WP2_CHECK_STATUS(occupancy_size_.CopyInternal(other.occupancy_size_));
WP2_CHECK_ALLOC_OK(size_stack_.copy_from(other.size_stack_));
- WP2_CHECK_ALLOC_OK(blocks_.copy_from(other.blocks_));
- WP2_CHECK_ALLOC_OK(size_indices_.copy_from(other.size_indices_));
next_ = other.next_;
return WP2_STATUS_OK;
}
@@ -216,7 +214,6 @@
x, y, snapped_ ? GetSnappedBlockSize(x, y, w, h) : GetBlockSize(w, h));
}
-const Vector_u16& FrontMgrNxNBase::SizeIndices() const { return size_indices_; }
//------------------------------------------------------------------------------
@@ -262,39 +259,31 @@
block.w() <= next_.w() && block.h() <= next_.h());
}
-WP2Status FrontMgrLexico::Sort() {
- std::sort(blocks_.begin(), blocks_.end());
+WP2Status FrontMgrLexico::Sort(VectorNoCtor<Block>& blocks,
+ Vector_u16& size_order_indices) const {
+ std::sort(blocks.begin(), blocks.end());
// Block sizes are written to the stream in the same order as the blocks.
- WP2_CHECK_ALLOC_OK(size_indices_.resize(blocks_.size()));
- std::iota(size_indices_.begin(), size_indices_.end(), 0);
+ WP2_CHECK_ALLOC_OK(size_order_indices.resize(blocks.size()));
+ std::iota(size_order_indices.begin(), size_order_indices.end(), 0);
// Only CheckBlockList() in debug but don't assert WP2_STATUS_OUT_OF_MEMORY.
WP2Status status = WP2_STATUS_OK;
- assert((status = CheckBlockList(), true)); // NOLINT (side effect assert)
+ assert((status = CheckBlockList(blocks), true)); // NOLINT side effect assert
WP2_CHECK_STATUS(status);
return WP2_STATUS_OK;
}
-WP2Status FrontMgrLexico::CheckBlockList() const {
+WP2Status FrontMgrLexico::CheckBlockList(
+ const VectorNoCtor<Block>& blocks) const {
FrontMgrLexico mgr;
const uint32_t width = bwidth_ * kMinBlockSizePix;
const uint32_t height = bheight_ * kMinBlockSizePix;
WP2_CHECK_STATUS(mgr.Init(partition_set_, snapped_, width, height));
- for (uint32_t i = 0; i < blocks_.size(); ++i) {
- const Block& v = blocks_[i];
+ for (uint32_t i = 0; i < blocks.size(); ++i) {
+ const Block& v = blocks[i];
const Block b(mgr.next_.x(), mgr.next_.y(), v.dim());
// Compare to the input block.
- const uint32_t bw = BlockWidth[v.dim()];
- const uint32_t bh = BlockHeight[v.dim()];
- if (!(bw <= b.w() && bh <= b.h()) ||
- !(bw > 0 && bw <= kMaxBlockSize && bh > 0 && bh <= kMaxBlockSize)) {
- fprintf(stderr,
- "Block validation error: size is too large! "
- "@%d,%d: v=%dx%d (w/h=%d,%d) b=%dx%d\n",
- v.x(), v.y(), bw, bh, width, height, b.w(), b.h());
- assert(false);
- }
if (!(b.x() == v.x() && b.y() == v.y())) {
fprintf(stderr, "Block validation error: wrong x,y position! "
"@%d,%d: expected %d,%d\n", v.x(), v.y(), b.x(), b.y());
@@ -394,21 +383,28 @@
// Though this algorithm is O(N^2) in the number of blocks, it is actually O(N)
// in practice as the initial blocks are sorted and when searching for
// neighboring blocks, they are not far in that list.
-WP2Status FrontMgrMax::Sort() {
- Clear();
+WP2Status FrontMgrMax::Sort(VectorNoCtor<Block>& blocks,
+ Vector_u16& size_order_indices) const {
+ // Sort() is const, we don't want to modify this instance's state, so we
+ // use a new instance for sorting purposes.
+ FrontMgrMax mgr_tmp;
+ WP2_CHECK_STATUS(mgr_tmp.Init(partition_set_, snapped_,
+ bwidth_ * kMinBlockSizePix,
+ bheight_ * kMinBlockSizePix));
+
uint32_t ind = 0;
// blocks_size will contain the blocks in size order while blocks_ contains
// the blocks sorted in block order.
VectorNoCtor<WP2::Block> blocks_size;
- WP2_CHECK_ALLOC_OK(blocks_size.reserve(blocks_.size()));
- while (ind < blocks_.size()) {
+ WP2_CHECK_ALLOC_OK(blocks_size.reserve(blocks.size()));
+ while (ind < blocks.size()) {
uint32_t best_ind = ind;
- if (size_stack_.empty()) {
+ if (mgr_tmp.size_stack_.empty()) {
// If we have no queue of elements to check, find the leftmost block at
// lowest heights.
- Block best = blocks_[ind];
- for (uint32_t i = ind + 1; i < blocks_.size(); ++i) {
- const Block& tmp = blocks_[i];
+ Block best = blocks[ind];
+ for (uint32_t i = ind + 1; i < blocks.size(); ++i) {
+ const Block& tmp = blocks[i];
if (tmp.y() < best.y() || (tmp.y() == best.y() && tmp.x() < best.x())) {
best = tmp;
best_ind = i;
@@ -417,52 +413,52 @@
} else {
// If the left context is not full, find the first block that can fill
// it.
- const uint32_t x = size_stack_.back().block.x() - 1;
- const uint32_t y = occupancy_size_.GetOccupancy(x);
- best_ind = blocks_.size();
- for (uint32_t i = ind; i < blocks_.size(); ++i) {
- const Block& b = blocks_[i];
+ const uint32_t x = mgr_tmp.size_stack_.back().block.x() - 1;
+ const uint32_t y = mgr_tmp.occupancy_size_.GetOccupancy(x);
+ best_ind = blocks.size();
+ for (uint32_t i = ind; i < blocks.size(); ++i) {
+ const Block& b = blocks[i];
if (b.x() <= x && x < b.x() + b.w() && b.y() <= y &&
y < b.y() + b.h()) {
best_ind = i;
break;
}
}
- assert(best_ind < blocks_.size());
+ assert(best_ind < blocks.size());
}
// Add that new block to the list of blocks.
- const Block& block = blocks_[best_ind];
+ const Block& block = blocks[best_ind];
WP2_CHECK_ALLOC_OK(blocks_size.push_back(block));
Block tmp;
- WP2_CHECK_ALLOC_OK(UseSize(block.dim(), best_ind, &tmp));
+ WP2_CHECK_ALLOC_OK(mgr_tmp.UseSize(block.dim(), best_ind, &tmp));
assert(block == tmp);
// Empty the queue if needed.
while (true) {
Info info;
- if (!UseFinal(&info)) break;
+ if (!mgr_tmp.UseFinal(&info)) break;
const Block blk = info.block;
// Place the block at its right spot.
- for (uint32_t i = ind; i < blocks_.size(); ++i) {
- if (blocks_[i] == blk) {
- std::swap(blocks_[i], blocks_[ind]);
+ for (uint32_t i = ind; i < blocks.size(); ++i) {
+ if (blocks[i] == blk) {
+ std::swap(blocks[i], blocks[ind]);
++ind;
break;
}
}
}
- UpdateNextBlock();
- if (ind == blocks_.size()) break;
+ mgr_tmp.UpdateNextBlock();
+ if (ind == blocks.size()) break;
}
// Convert blocks_size to indices.
- WP2_CHECK_ALLOC_OK(size_indices_.resize(blocks_.size()));
- std::iota(size_indices_.begin(), size_indices_.end(), 0);
+ WP2_CHECK_ALLOC_OK(size_order_indices.resize(blocks.size()));
+ std::iota(size_order_indices.begin(), size_order_indices.end(), 0);
ind = 0;
for (const Block& b : blocks_size) {
- for (uint32_t i = ind; i < blocks_.size(); ++i) {
- if (blocks_[size_indices_[i]] == b) {
- std::swap(size_indices_[i], size_indices_[ind]);
+ for (uint32_t i = ind; i < blocks.size(); ++i) {
+ if (blocks[size_order_indices[i]] == b) {
+ std::swap(size_order_indices[i], size_order_indices[ind]);
++ind;
break;
}
@@ -471,17 +467,17 @@
// Only CheckBlockList() in debug but don't assert WP2_STATUS_OUT_OF_MEMORY.
WP2Status status = WP2_STATUS_OK;
- assert((status = CheckBlockList(), true)); // NOLINT (side effect assert)
+ assert((status = CheckBlockList(blocks), true)); // NOLINT side effect assert
WP2_CHECK_STATUS(status);
return WP2_STATUS_OK;
}
-WP2Status FrontMgrMax::CheckBlockList() const {
+WP2Status FrontMgrMax::CheckBlockList(const VectorNoCtor<Block>& blocks) const {
FrontMgrBase occupancy;
WP2_CHECK_STATUS(occupancy.InitBase(bwidth_ * kMinBlockSizePix,
bheight_ * kMinBlockSizePix));
- for (const Block& b : blocks_) {
+ for (const Block& b : blocks) {
// Check we have context above.
if (b.y() > 0) {
for (uint32_t x = b.x(); x < b.x() + b.w(); ++x) {
@@ -492,7 +488,7 @@
}
}
// Check we have context on the left.
- if (!IsFinal(b)) {
+ if (!DoIsFinal(occupancy, b)) {
fprintf(stderr, "Context not good at %d %d ", b.x(), b.y());
assert(false);
}
@@ -502,7 +498,13 @@
}
bool FrontMgrMax::IsFinal(const WP2::Block& block) const {
- return (block.x() == 0 || occupancy_[block.x() - 1] >= block.y() + block.h());
+ return DoIsFinal(*this, block);
+}
+
+bool FrontMgrMax::DoIsFinal(const FrontMgrBase& occupancy,
+ const WP2::Block& block) const {
+ return (block.x() == 0 ||
+ occupancy.GetOccupancy(block.x() - 1) >= block.y() + block.h());
}
bool FrontMgrMax::IsFinalSize(const WP2::Block& block) const {
@@ -555,12 +557,13 @@
return true;
}
-WP2Status FrontMgrArea::Sort() {
- std::sort(blocks_.begin(), blocks_.end(),
+WP2Status FrontMgrArea::Sort(VectorNoCtor<Block>& blocks,
+ Vector_u16& size_order_indices) const {
+ std::sort(blocks.begin(), blocks.end(),
Comp(kMaxTileSize / kMinBlockSizePix, area_width_, area_height_));
// Same block and size order.
- WP2_CHECK_ALLOC_OK(size_indices_.resize(blocks_.size()));
- std::iota(size_indices_.begin(), size_indices_.end(), 0);
+ WP2_CHECK_ALLOC_OK(size_order_indices.resize(blocks.size()));
+ std::iota(size_order_indices.begin(), size_order_indices.end(), 0);
return WP2_STATUS_OK;
}
diff --git a/src/utils/front_mgr.h b/src/utils/front_mgr.h
index c828747..e6dd617 100644
--- a/src/utils/front_mgr.h
+++ b/src/utils/front_mgr.h
@@ -128,17 +128,11 @@
void Clear() override;
- // Returns all the underlying blocks of the tile, in arbitrary order(?)
- // or in block order if Sort() has been called.
- const VectorNoCtor<Block>& Blocks() const { return blocks_; }
- VectorNoCtor<Block>& Blocks() { return blocks_; }
-
- // Returns the indices of the blocks in Blocks() (that are sorted in block
- // order) so that they are in size order.
- const Vector_u16& SizeIndices() const;
-
- // Sorts the Blocks() in block order.
- virtual WP2Status Sort() = 0;
+ // Sorts the given blocks in block order and fills 'size_order_indices' with
+ // the indices of a permutation of 'blocks' that puts it in size order (order
+ // in which block sizes are written).
+ virtual WP2Status Sort(VectorNoCtor<Block>& blocks,
+ Vector_u16& size_order_indices) const = 0;
// Block-order related functions.
@@ -185,8 +179,6 @@
// rest of the block is written.
VectorNoCtor<Info> size_stack_;
FrontMgrBase occupancy_size_;
- VectorNoCtor<Block> blocks_;
- Vector_u16 size_indices_;
// Next max possible block (for reading/writing block sizes).
Block next_;
};
@@ -207,12 +199,13 @@
WP2_NO_DISCARD
bool UseSize(BlockSize dim, uint32_t ind, Block* const block) override;
virtual void UndoUseSize(const Block& block);
- WP2Status Sort() override;
+ WP2Status Sort(VectorNoCtor<Block>& blocks,
+ Vector_u16& size_order_indices) const override;
bool IsFinal(const WP2::Block& block) const override;
private:
// Returns whether the 'Blocks()' are in the order they will be written.
- WP2Status CheckBlockList() const;
+ WP2Status CheckBlockList(const VectorNoCtor<Block>& blocks) const;
};
//------------------------------------------------------------------------------
@@ -227,16 +220,18 @@
bool TryGetNextBlock(BlockSize size, Block* const block) const override;
WP2_NO_DISCARD
bool UseSize(BlockSize dim, uint32_t ind, Block* const block) override;
- WP2Status Sort() override;
+ WP2Status Sort(VectorNoCtor<Block>& blocks,
+ Vector_u16& size_order_indices) const override;
bool IsFinal(const WP2::Block& block) const override;
private:
+ bool DoIsFinal(const FrontMgrBase& occupancy, const WP2::Block& block) const;
// Returns true if a block is considered final in the size occupancy.
bool IsFinalSize(const WP2::Block& block) const;
// Updates the 'next_' block.
void UpdateNextBlock();
// Returns whether the 'Blocks()' are in the order they will be written.
- WP2Status CheckBlockList() const;
+ WP2Status CheckBlockList(const VectorNoCtor<Block>& blocks) const;
};
// This is the FrontMgr class that should be used by default.
@@ -283,7 +278,8 @@
bool TryGetNextBlock(BlockSize size, Block* const block) const override;
WP2_NO_DISCARD
bool UseSize(BlockSize dim, uint32_t ind, Block* const block) override;
- WP2Status Sort() override;
+ WP2Status Sort(VectorNoCtor<Block>& blocks,
+ Vector_u16& size_order_indices) const override;
bool IsFinal(const WP2::Block& block) const override;
protected:
diff --git a/src/utils/quantizer.cc b/src/utils/quantizer.cc
index 01f76cb..ab4d53b 100644
--- a/src/utils/quantizer.cc
+++ b/src/utils/quantizer.cc
@@ -32,14 +32,31 @@
WP2Status Quantizer::Allocate(uint32_t range_max) {
// We need at least kMaxFreqBits elements to store Huffman probabilities.
histogram_size_max_ = std::max(kMaxFreqBits + 1u, range_max);
- const size_t histogram_size = 4 * sizeof(uint32_t) + sizeof(uint16_t);
- WP2_CHECK_STATUS(buffer_.Resize(
- kConfigNbr * histogram_size_max_ * histogram_size, /*keep_bytes=*/false));
+ WP2_CHECK_STATUS(
+ buffer32_.Resize(kConfigNbr * histogram_size_max_ * 4 * sizeof(uint32_t),
+ /*keep_bytes=*/false));
+ WP2_CHECK_STATUS(
+ buffer16_.Resize(kConfigNbr * histogram_size_max_ * sizeof(uint16_t),
+ /*keep_bytes=*/false));
+ uint32_t* buffer32 = (uint32_t*)buffer32_.bytes;
+ uint16_t* buffer16 = (uint16_t*)buffer16_.bytes;
+ for (Config& c : configs_) {
+ c.histogram_quantized = buffer32;
+ buffer32 += histogram_size_max_;
+ c.histogram_to_write = buffer32;
+ buffer32 += histogram_size_max_;
+ c.tmp_histogram_to_write = buffer32;
+ buffer32 += histogram_size_max_;
+ c.histo.counts = buffer32;
+ buffer32 += histogram_size_max_;
+ c.histo.mapping = buffer16;
+ buffer16 += histogram_size_max_;
+ }
- for (size_t i = 0; i < kConfigNbr; ++i) {
+ for (auto& c : configs_) {
// Make sure the recursion buffers are properly allocated.
- WP2_CHECK_ALLOC_OK(histogram_sub_[i].resize(kMaxFreqBits + 1));
- WP2_CHECK_ALLOC_OK(mapping_sub_[i].resize(kMaxFreqBits + 1));
+ WP2_CHECK_ALLOC_OK(c.histogram_sub.resize(kMaxFreqBits + 1));
+ WP2_CHECK_ALLOC_OK(c.mapping_sub.resize(kMaxFreqBits + 1));
}
WP2_CHECK_ALLOC_OK(stats_buffer_.resize(histogram_size_max_));
@@ -52,25 +69,11 @@
Config** const config_best) {
assert(effort >= 0 && effort <= 9);
*config_best = &configs_[0];
- configs_used_[0] = true;
- for (size_t i = 1; i < kConfigNbr; ++i) configs_used_[i] = false;
-
- uint32_t* buffer = (uint32_t*)buffer_.bytes;
- for (size_t i = 0; i < kConfigNbr; ++i) {
- // Make sure the recursion buffers are properly allocated.
- histogram_quantized_[i] = buffer;
- buffer += histogram_size_max_;
- histogram_to_write_[i] = buffer;
- buffer += histogram_size_max_;
- configs_[i].histogram_to_write = buffer;
- buffer += histogram_size_max_;
- configs_[i].histo.counts = buffer;
- buffer += histogram_size_max_;
- configs_[i].histo.mapping = (uint16_t*)buffer;
- buffer += histogram_size_max_ * sizeof(uint16_t) / sizeof(uint32_t);
- }
+ for (uint32_t i = 0; i < kConfigNbr; ++i) configs_->used = false;
+ (*config_best)->used = true;
QuantizeImpl(histogram, mapping, size_sparse, symbol_range,
- 1 + WP2Log2Floor(max_count), effort, 0);
+ 1 + WP2Log2Floor(max_count), effort,
+ /*cost_max=*/std::numeric_limits<float>::max(), *config_best);
}
// The quantization implementation uses the Config cache of the class during
@@ -78,29 +81,27 @@
void Quantizer::QuantizeImpl(const uint32_t* const histogram,
const uint16_t* const mapping, size_t size_sparse,
uint32_t symbol_range, uint32_t n_pixels_bits,
- int effort, size_t config_index, float cost_max) {
- assert(config_index < kConfigNbr);
- Config* const config_best = &configs_[config_index];
+ int effort, float cost_max, Config* const config) {
+ assert(config != nullptr);
if (size_sparse == 0) {
- config_best->param.type = Raw;
- config_best->param.is_sparse = false;
- config_best->param.max_freq_bits = 0;
- config_best->histogram_to_write = nullptr;
- config_best->size_to_write = 0;
- config_best->histo.counts = nullptr;
- config_best->histo.mapping = nullptr;
- config_best->histo.nnz = 0;
- config_best->cost = 0;
+ config->param.type = Raw;
+ config->param.is_sparse = false;
+ config->param.max_freq_bits = 0;
+ config->histogram_to_write = nullptr;
+ config->size_to_write = 0;
+ config->histo.counts = nullptr;
+ config->histo.mapping = nullptr;
+ config->histo.nnz = 0;
+ config->cost = 0;
return;
}
// We simplify the mapping to be stored as the difference between
// consecutive terms.
- config_best->histo.nnz = size_sparse;
- std::copy(mapping, mapping + size_sparse, config_best->histo.mapping);
+ config->histo.nnz = size_sparse;
+ std::copy(mapping, mapping + size_sparse, config->histo.mapping);
// Pre-compute some quantization configurations for clarity.
- uint8_t* const bits = bits_[config_index];
size_t n_max_freq_bits = 0;
{
uint32_t max_freq_bits_max =
@@ -108,23 +109,14 @@
max_freq_bits_max = std::min(max_freq_bits_max, kMaxFreqBits);
const uint32_t max_freq_bits_min =
(1 * effort + max_freq_bits_max * (9 - effort)) / 9;
- for (uint32_t max_freq_bits = max_freq_bits_max;
- max_freq_bits >= max_freq_bits_min; --max_freq_bits) {
- bits[n_max_freq_bits++] = max_freq_bits;
- }
- // Start by doing some strong quantization to prune out the ones that would
- // barely change the bits cost.
- std::swap(bits[0], bits[(n_max_freq_bits - 1) / 2]);
- if (n_max_freq_bits > 1) {
- std::swap(bits[1], bits[(n_max_freq_bits - 1) / 4]);
- }
- if (n_max_freq_bits > 2) {
- std::swap(bits[2], bits[(n_max_freq_bits - 1) * 3 / 4]);
+ for (uint32_t max_freq_bits = max_freq_bits_min;
+ max_freq_bits <= max_freq_bits_max; ++max_freq_bits) {
+ config->bits[n_max_freq_bits++] = max_freq_bits;
}
}
- uint32_t* histogram_quantized = histogram_quantized_[config_index];
- uint32_t* histogram_to_write = histogram_to_write_[config_index];
+ uint32_t* histogram_quantized = config->histogram_quantized;
+ uint32_t* histogram_to_write = config->tmp_histogram_to_write;
// Compute some constant costs.
float cost_probability_size, cost_mapping;
@@ -138,7 +130,7 @@
cost_probability_size = WP2Log2(symbol_range + 1 - size_sparse);
// Small speed improvements: if we use the whole range, no need to even
// consider a potential mapping.
- cost_mapping = StoreMapping(config_best->histo.mapping, size_sparse,
+ cost_mapping = StoreMapping(config->histo.mapping, size_sparse,
symbol_range, stats_buffer_.data(), nullptr);
}
// Cost for the sparse bit and the histogram type.
@@ -146,15 +138,15 @@
n_pixels_bits = std::min(n_pixels_bits, kMaxFreqBits);
// Go over the quantification configurations and pick the best one.
- config_best->cost = cost_max;
+ config->cost = cost_max;
for (size_t i = 0; i < n_max_freq_bits; ++i) {
// No need to continue if any pre-computed cost we have is already bigger.
- if (cost_sparse_bit_and_type + cost_mapping > config_best->cost &&
- cost_sparse_bit_and_type + cost_probability_size > config_best->cost) {
+ if (cost_sparse_bit_and_type + cost_mapping > config->cost &&
+ cost_sparse_bit_and_type + cost_probability_size > config->cost) {
break;
}
for (const ConfigType type : {Raw, Huffman}) {
- uint8_t max_freq_bits = bits[i];
+ uint8_t max_freq_bits = config->bits[i];
// Compute the cost of storing the data with the quantized probabilities.
float cost_ini;
@@ -175,14 +167,14 @@
for (const bool is_sparse : {false, true}) {
// Reset variables.
- max_freq_bits = bits[i];
+ max_freq_bits = config->bits[i];
float cost = cost_ini;
// Add the cost for the mapping or the probability size.
cost += is_sparse ? cost_mapping : cost_probability_size;
// No need to continue if the bit cost without the histogram cost is
// already bigger.
- if (cost >= config_best->cost) continue;
+ if (cost >= config->cost) continue;
// Prepare the vector in which we will write the histogram.
size_t histogram_to_write_size;
@@ -248,29 +240,29 @@
cost += cost_histo;
// Keep the best configuration.
- if (cost >= config_best->cost) {
+ if (cost >= config->cost) {
continue;
}
- config_best->param.type = type;
- config_best->param.is_sparse = is_sparse;
- config_best->param.max_freq_bits = max_freq_bits;
- config_best->size_to_write = histogram_to_write_size;
- std::swap(config_best->histogram_to_write, histogram_to_write);
+ config->param.type = type;
+ config->param.is_sparse = is_sparse;
+ config->param.max_freq_bits = max_freq_bits;
+ config->size_to_write = histogram_to_write_size;
+ std::swap(config->histogram_to_write, histogram_to_write);
if (is_sparse) {
- std::swap(config_best->histo.counts, histogram_quantized);
+ std::swap(config->histo.counts, histogram_quantized);
} else {
std::copy(histogram_quantized,
histogram_quantized + histogram_to_write_size,
- config_best->histo.counts);
+ config->histo.counts);
}
- config_best->cost = cost;
+ config->cost = cost;
}
}
}
// Reset the common temporary variables.
- histogram_quantized_[config_index] = histogram_quantized;
- histogram_to_write_[config_index] = histogram_to_write;
+ config->histogram_quantized = histogram_quantized;
+ config->tmp_histogram_to_write = histogram_to_write;
}
} // namespace WP2
diff --git a/src/utils/quantizer.h b/src/utils/quantizer.h
index c576842..d25842b 100644
--- a/src/utils/quantizer.h
+++ b/src/utils/quantizer.h
@@ -63,11 +63,22 @@
size_t size_to_write;
HistogramSparse histo;
float cost;
- };
- Quantizer() {
- for (auto& c : configs_used_) c = false;
- }
+ // Filled by QuantizeImpl():
+ void Reset() { used = false; }
+
+ private:
+ bool used = false;
+ // For each recursion level, each set of param can be Raw/Huffman, sparse or
+ // not and have several levels of recursion.
+ uint8_t bits[kMaxFreqBits];
+ Vector_u32 histogram_sub;
+ Vector_u16 mapping_sub;
+
+ uint32_t* histogram_quantized;
+ uint32_t* tmp_histogram_to_write;
+ friend Quantizer;
+ };
// range_max is the maximum range of the used symbols (maximum value + 1).
WP2Status Allocate(uint32_t range_max);
@@ -83,35 +94,21 @@
int effort, Config** const config_best);
private:
- // Free the config from the buffer to make it re-usable.
- void ResetConfig(const Config* c) {
- const size_t c_ind = c - &configs_[0];
- configs_used_[c_ind] = false;
- }
-
// Implementation of the quantization that can call itself to compress its own
// coefficients.
// 'cost_max' is the value above which we can early exit.
void QuantizeImpl(const uint32_t* const histogram,
const uint16_t* const mapping, size_t size_sparse,
uint32_t symbol_range, uint32_t n_pixels_bits, int effort,
- size_t config_index,
- float cost_max = std::numeric_limits<float>::max());
+ float cost_max, Config* const config);
// TODO(vrabaud) Investigate to see if it is worth having more levels.
static constexpr size_t kConfigNbr = 2;
Config configs_[kConfigNbr];
- bool configs_used_[kConfigNbr];
- // For each recursion level, each set of param can be Raw/Huffman, sparse or
- // not and have several levels of recursion.
- uint8_t bits_[kConfigNbr][kMaxFreqBits];
- Vector_u32 histogram_sub_[kConfigNbr];
- Vector_u16 mapping_sub_[kConfigNbr];
-
uint32_t histogram_size_max_;
- uint32_t* histogram_quantized_[kConfigNbr];
- uint32_t* histogram_to_write_[kConfigNbr];
- Data buffer_; // Big memory chunk storing the buffers above.
+
+ Data buffer32_; // Big memory chunk storing the uint32_t buffers above.
+ Data buffer16_; // Big memory chunk storing the uint16_t buffers above.
VectorNoCtor<OptimizeArrayStorageStat> stats_buffer_;
};
diff --git a/tests/test_ans.cc b/tests/test_ans.cc
index 44e039c..3e20d81 100644
--- a/tests/test_ans.cc
+++ b/tests/test_ans.cc
@@ -625,27 +625,29 @@
EXPECT_WP2_OK(quantizer.Allocate(kMaxSymbol));
Quantizer::Config* config = nullptr;
- quantizer.Quantize(histogram.data(), mapping.data(), size_sparse, kMaxSymbol,
- /*max_count=*/16, /*effort=*/5, &config);
+ for (int effort : {0, 5, 9}) {
+ quantizer.Quantize(histogram.data(), mapping.data(), size_sparse,
+ kMaxSymbol, /*max_count=*/16, effort, &config);
- // Display results.
- if (kVerbose) {
- printf("Cost: %f\n", config->cost);
- if (config->param.is_sparse) {
- printf("Histogram is sparse:\n(index, count - 1):\n");
- for (uint32_t i = 0; i < config->size_to_write; ++i) {
- printf("(%d,%d) ", mapping[i], config->histogram_to_write[i]);
+ // Display results.
+ if (kVerbose) {
+ printf("Cost: %f\n", config->cost);
+ if (config->param.is_sparse) {
+ printf("Histogram is sparse:\n(index, count - 1):\n");
+ for (uint32_t i = 0; i < config->size_to_write; ++i) {
+ printf("(%d,%d) ", mapping[i], config->histogram_to_write[i]);
+ }
+ printf("\n");
+ } else {
+ printf("Histogram is not sparse:\n");
+ for (uint32_t i = 0; i < config->size_to_write; ++i) {
+ printf("%d ", config->histogram_to_write[i]);
+ }
+ printf("\n");
}
- printf("\n");
- } else {
- printf("Histogram is not sparse:\n");
- for (uint32_t i = 0; i < config->size_to_write; ++i) {
- printf("%d ", config->histogram_to_write[i]);
+ if (config->param.type == Quantizer::ConfigType::Huffman) {
+ printf("The counts above should be interpreted as exponents of 2.\n");
}
- printf("\n");
- }
- if (config->param.type == Quantizer::ConfigType::Huffman) {
- printf("The counts above should be interpreted as exponents of 2.\n");
}
}
}
diff --git a/tests/test_aom_residuals.cc b/tests/test_aom_residuals.cc
index 06fc0a1..bd6f736 100644
--- a/tests/test_aom_residuals.cc
+++ b/tests/test_aom_residuals.cc
@@ -62,7 +62,7 @@
std::unique_ptr<WP2::SymbolWriter>
sw(new (WP2Allocable::nothrow) WP2::SymbolWriter);
ASSERT_TRUE(sw != nullptr);
- ASSERT_WP2_OK(sw->Init(info));
+ ASSERT_WP2_OK(sw->Init(info, /*effort=*/5));
ASSERT_WP2_OK(sw->Allocate());
SymbolRecorder recorder;
ASSERT_WP2_OK(recorder.Allocate(info, /*num_records=*/num_iters));
diff --git a/tests/test_coded_block.cc b/tests/test_coded_block.cc
index 4dbc1d4..2d6f4f8 100644
--- a/tests/test_coded_block.cc
+++ b/tests/test_coded_block.cc
@@ -112,7 +112,7 @@
ASSERT_TRUE(transforms.push_back(kDctDct));
BlockContext context;
- WP2_ASSERT_STATUS(context.Init(/*use_aom=*/false, width, height));
+ WP2_ASSERT_STATUS(context.Init(/*use_aom=*/false));
ASSERT_WP2_OK(cb.FindBestPredTf(
EncoderConfig::kDefault, tile_rect, predictors, segment, context,
kYChannel, kNumChannels, /*reduced=*/false, transforms, &counters));
diff --git a/tests/test_front_mgr.cc b/tests/test_front_mgr.cc
index b39d510..5d21830 100644
--- a/tests/test_front_mgr.cc
+++ b/tests/test_front_mgr.cc
@@ -100,22 +100,23 @@
FrontMgrMax mgr_max;
FrontMgrArea mgr_area(kAreaSize, kAreaSize);
+ VectorNoCtor<Block> blocks;
+ Vector_u16 size_order_indices;
FrontMgrNxNBase* const mgr =
GetMgr(front_mgr_type, &mgr_lex, &mgr_max, &mgr_area);
- CreateData(w, h, GetSnapped(front_mgr_type), &gen, &mgr->Blocks());
+ CreateData(w, h, GetSnapped(front_mgr_type), &gen, &blocks);
ASSERT_WP2_OK(mgr->Init(ALL_RECTS, GetSnapped(front_mgr_type), w, h));
- ASSERT_WP2_OK(mgr->Sort());
- ASSERT_EQ(mgr->Blocks().size(), mgr->SizeIndices().size());
+ ASSERT_WP2_OK(mgr->Sort(blocks, size_order_indices));
+ ASSERT_EQ(blocks.size(), size_order_indices.size());
// Check all indices are used only once.
- ASSERT_EQ(
- mgr->Blocks().size(),
- std::set<uint16_t>(mgr->SizeIndices().begin(), mgr->SizeIndices().end())
- .size());
+ ASSERT_EQ(blocks.size(), std::set<uint16_t>(size_order_indices.begin(),
+ size_order_indices.end())
+ .size());
// Go over all indices and make sure it works.
mgr->Clear();
- for (uint16_t i : mgr->SizeIndices()) {
- const Block& block = mgr->Blocks()[i];
+ for (uint16_t i : size_order_indices) {
+ const Block& block = blocks[i];
const Block max_block = mgr->GetMaxPossibleBlock();
ASSERT_GE(block.x(), max_block.x());
@@ -162,14 +163,16 @@
ASSERT_WP2_OK(mgr->Init(ALL_RECTS, GetSnapped(front_mgr_type), w, h));
- CreateData(w, h, GetSnapped(front_mgr_type), &gen, &mgr->Blocks());
- ASSERT_WP2_OK(mgr->Sort());
+ VectorNoCtor<Block> blocks;
+ Vector_u16 size_order_indices;
+
+ CreateData(w, h, GetSnapped(front_mgr_type), &gen, &blocks);
+ ASSERT_WP2_OK(mgr->Sort(blocks, size_order_indices));
mgr->Clear(); // Sort() messes up the FrontMgr state so clear it.
- int32_t num_blocks_before_cloning =
- gen.Get<int32_t>(1, mgr->Blocks().size());
+ int32_t num_blocks_before_cloning = gen.Get<int32_t>(1, blocks.size());
- for (uint16_t i : mgr->SizeIndices()) {
+ for (uint16_t i : size_order_indices) {
if (num_blocks_before_cloning == 0) {
ASSERT_WP2_OK((front_mgr_type == kLexico)
? mgr_lex_clone.CopyFrom(mgr_lex)
@@ -178,24 +181,21 @@
: mgr_area_clone.CopyFrom(mgr_area));
}
- const Block& block = mgr->Blocks()[i];
+ const Block& block = blocks[i];
Block block_tmp;
ASSERT_TRUE(mgr->TryGetNextBlock(block.dim(), &block_tmp));
if (num_blocks_before_cloning <= 0) {
// The clone was copied. Verify that it returns the same values as the
// original 'map' and apply the same modifications to it from now on.
- const Block& block_clone = mgr_clone->Blocks()[i];
Block block_tmp_clone;
- ASSERT_TRUE(
- mgr_clone->TryGetNextBlock(block_clone.dim(), &block_tmp_clone));
+ ASSERT_TRUE(mgr_clone->TryGetNextBlock(block.dim(), &block_tmp_clone));
- ASSERT_EQ(block, block_clone);
ASSERT_EQ(block_tmp, block_tmp_clone);
ASSERT_EQ(mgr->Done(), mgr_clone->Done());
- ASSERT_TRUE(mgr_clone->UseSize(
- block_clone.dim(), /*ind=*/0u, &block_tmp_clone));
+ ASSERT_TRUE(
+ mgr_clone->UseSize(block.dim(), /*ind=*/0u, &block_tmp_clone));
while (mgr_clone->UseFinal()) {
}
}
diff --git a/tests/test_quant_mtx.cc b/tests/test_quant_mtx.cc
index de6dafc..51085de 100644
--- a/tests/test_quant_mtx.cc
+++ b/tests/test_quant_mtx.cc
@@ -320,7 +320,7 @@
sw(new (WP2Allocable::nothrow) WP2::SymbolWriter);
ASSERT_TRUE(sw != nullptr);
- ASSERT_WP2_OK(sw->Init(symbols_info));
+ ASSERT_WP2_OK(sw->Init(symbols_info, /*effort=*/5));
ASSERT_WP2_OK(sw->Allocate());
const int16_t yuv_min = -512;
@@ -350,7 +350,6 @@
TypeParam mgr;
ASSERT_WP2_OK(
mgr.Init(ALL_RECTS, /*snapped=*/false, rect.width, rect.height));
- EXPECT_TRUE(mgr.Blocks().resize(1));
cb.SetRange(yuv_min, yuv_max);
cb.SetDim(/*block=*/{/*x=*/0, /*y=*/0, /*dim=*/block_size}, mgr);
cb.y_context_is_constant_ = false;
@@ -399,6 +398,7 @@
cb.coeffs_[kVChannel][tf_i],
&cb.num_coeffs_[kVChannel][tf_i]);
+ mgr.Clear();
SymbolRecorder recorder;
ASSERT_WP2_OK(recorder.Allocate(symbols_info, /*num_records=*/0));
Counters counters;
@@ -426,7 +426,11 @@
ASSERT_WP2_OK(syntax_writer.Record(cb));
ASSERT_WP2_OK(syntax_writer.RecordSize(mgr, cb.dim()));
ASSERT_WP2_OK(syntax_writer.WriteHeader(&enc));
- ASSERT_WP2_OK(syntax_writer.WriteBlocks(cblocks, &mgr, &enc));
+ Vector_u16 size_order_indices;
+ ASSERT_TRUE(size_order_indices.resize(cblocks.size()));
+ std::iota(size_order_indices.begin(), size_order_indices.end(), 0);
+ ASSERT_WP2_OK(
+ syntax_writer.WriteBlocks(cblocks, size_order_indices, &mgr, &enc));
}
}
}
diff --git a/tests/test_symbols.cc b/tests/test_symbols.cc
index 7cc5622..82249a0 100644
--- a/tests/test_symbols.cc
+++ b/tests/test_symbols.cc
@@ -177,7 +177,7 @@
void WriteHeader(const SymbolsInfoTest& info, const SymbolRecorder& recorder,
uint32_t* max_nnz, ANSDictionaries* const dicts,
ANSEnc* const enc, SymbolWriter* const sw) {
- ASSERT_WP2_OK(sw->Init(info));
+ ASSERT_WP2_OK(sw->Init(info, /*effort=*/5));
ASSERT_WP2_OK(sw->Allocate());
// Get the maximum number of non-zero values by aggregating over all
// clusters.
@@ -644,7 +644,7 @@
std::unique_ptr<WP2::SymbolWriter> sw(new (WP2Allocable::nothrow)
WP2::SymbolWriter);
ASSERT_TRUE(sw != nullptr);
- ASSERT_WP2_OK(sw->Init(info));
+ ASSERT_WP2_OK(sw->Init(info, /*effort=*/5));
ASSERT_WP2_OK(sw->Allocate());
ANSEnc enc;
ANSDictionaries dicts;
@@ -990,7 +990,7 @@
/*num_clusters=*/1, StorageMethod::kAuto);
SymbolWriterForTest sw;
- ASSERT_WP2_OK(sw.Init(info));
+ ASSERT_WP2_OK(sw.Init(info, /*effort=*/5));
ASSERT_WP2_OK(sw.Allocate());
sw.AddTrivial(kSymbol, kCluster, kValue);
@@ -1040,7 +1040,7 @@
StorageMethod::kAuto);
SymbolWriterForTest sw;
- ASSERT_WP2_OK(sw.Init(info));
+ ASSERT_WP2_OK(sw.Init(info, /*effort=*/5));
ASSERT_WP2_OK(sw.Allocate());
sw.AddRange(kSymbol, kCluster, /*mapping=*/nullptr, /*size=*/0,
kMaxSymbol + 1);
@@ -1096,7 +1096,7 @@
}
SymbolWriterForTest sw;
- ASSERT_WP2_OK(sw.Init(info));
+ ASSERT_WP2_OK(sw.Init(info, /*effort=*/5));
ASSERT_WP2_OK(sw.Allocate());
ANSDictionaries dicts;
@@ -1160,7 +1160,7 @@
}
SymbolWriterForTest sw;
- ASSERT_WP2_OK(sw.Init(info));
+ ASSERT_WP2_OK(sw.Init(info, /*effort=*/5));
ASSERT_WP2_OK(sw.Allocate());
ANSDictionaries dicts;
ASSERT_WP2_OK(sw.AddGolomb(kSymbol, kCluster, golomb_histogram.data(),
@@ -1215,7 +1215,7 @@
const uint32_t p0 = 3, p1 = 10;
SymbolWriterForTest sw;
- ASSERT_WP2_OK(sw.Init(info));
+ ASSERT_WP2_OK(sw.Init(info, /*effort=*/5));
ASSERT_WP2_OK(sw.Allocate());
ASSERT_WP2_OK(sw.AddAdaptiveBit(kSymbol, kCluster, p0, p1));
@@ -1267,7 +1267,7 @@
StorageMethod::kAdaptiveSym);
SymbolWriterForTest sw;
- ASSERT_WP2_OK(sw.Init(info));
+ ASSERT_WP2_OK(sw.Init(info, /*effort=*/5));
ASSERT_WP2_OK(sw.Allocate());
ASSERT_WP2_OK(sw.AddAdaptiveSymbol(
kSymbol, kCluster, (ANSAdaptiveSymbol::Method)method, speed));
@@ -1330,7 +1330,7 @@
ASSERT_TRUE(sw != nullptr);
ANSEnc enc;
ANSDictionaries dicts;
- ASSERT_WP2_OK(sw->Init(info));
+ ASSERT_WP2_OK(sw->Init(info, /*effort=*/5));
ASSERT_WP2_OK(sw->Allocate());
constexpr uint32_t max_nnz = 10000;
ASSERT_WP2_OK(sw->WriteHeader(/*sym=*/0, /*cluster=*/0, max_nnz, counts,
diff --git a/tests/test_syntax_writer.cc b/tests/test_syntax_writer.cc
index db86219..5c41deb 100644
--- a/tests/test_syntax_writer.cc
+++ b/tests/test_syntax_writer.cc
@@ -68,6 +68,7 @@
// Instances that will be needed after 'syntax_writer' is deleted.
Vector<CodedBlock> cblocks;
+ Vector_u16 size_order_indices;
FrontMgrLexico mgr;
float cost, cost_dicts;
uint32_t num_tokens;
@@ -90,6 +91,9 @@
ASSERT_TRUE(mgr.TryGetNextBlock(kBlocks[i], &block));
ASSERT_TRUE(cblocks.resize(cblocks.size() + 1));
+ ASSERT_TRUE(size_order_indices.resize(cblocks.size()));
+ std::iota(size_order_indices.begin(), size_order_indices.end(), 0);
+
CodedBlock& cb = cblocks.back();
cb.is420_ = false;
cb.id_ = AssignSegmentId(config, gparams, tile_rect, block);
@@ -137,7 +141,8 @@
ANSEnc enc;
mgr.Clear();
ASSERT_WP2_OK(syntax_writer.WriteHeader(&enc));
- ASSERT_WP2_OK(syntax_writer.WriteBlocks(cblocks, &mgr, &enc));
+ ASSERT_WP2_OK(
+ syntax_writer.WriteBlocks(cblocks, size_order_indices, &mgr, &enc));
cost = enc.GetCost();
cost_dicts = enc.GetCost(dicts);
@@ -151,7 +156,8 @@
ANSEnc enc_copy;
mgr.Clear();
ASSERT_WP2_OK(syntax_writer_copy.WriteHeader(&enc_copy));
- ASSERT_WP2_OK(syntax_writer_copy.WriteBlocks(cblocks, &mgr, &enc_copy));
+ ASSERT_WP2_OK(syntax_writer_copy.WriteBlocks(cblocks, size_order_indices,
+ &mgr, &enc_copy));
ASSERT_EQ(cost, enc_copy.GetCost());
ASSERT_EQ(cost_dicts, enc_copy.GetCost(dicts_copy));