|
@@ -585,6 +585,9 @@ static WEBP_INLINE score_t RDScoreTrellis(int lambda, score_t rate,
|
|
|
return rate * lambda + RD_DISTO_MULT * distortion;
|
|
|
}
|
|
|
|
|
|
+// Coefficient type.
|
|
|
+enum { TYPE_I16_AC = 0, TYPE_I16_DC = 1, TYPE_CHROMA_A = 2, TYPE_I4_AC = 3 };
|
|
|
+
|
|
|
static int TrellisQuantizeBlock(const VP8Encoder* const enc,
|
|
|
int16_t in[16], int16_t out[16],
|
|
|
int ctx0, int coeff_type,
|
|
@@ -593,7 +596,7 @@ static int TrellisQuantizeBlock(const VP8Encoder* const enc,
|
|
|
const ProbaArray* const probas = enc->proba_.coeffs_[coeff_type];
|
|
|
CostArrayPtr const costs =
|
|
|
(CostArrayPtr)enc->proba_.remapped_costs_[coeff_type];
|
|
|
- const int first = (coeff_type == 0) ? 1 : 0;
|
|
|
+ const int first = (coeff_type == TYPE_I16_AC) ? 1 : 0;
|
|
|
Node nodes[16][NUM_NODES];
|
|
|
ScoreState score_states[2][NUM_NODES];
|
|
|
ScoreState* ss_cur = &SCORE_STATE(0, MIN_DELTA);
|
|
@@ -657,16 +660,17 @@ static int TrellisQuantizeBlock(const VP8Encoder* const enc,
|
|
|
// test all alternate level values around level0.
|
|
|
for (m = -MIN_DELTA; m <= MAX_DELTA; ++m) {
|
|
|
Node* const cur = &NODE(n, m);
|
|
|
- int level = level0 + m;
|
|
|
+ const int level = level0 + m;
|
|
|
const int ctx = (level > 2) ? 2 : level;
|
|
|
const int band = VP8EncBands[n + 1];
|
|
|
score_t base_score;
|
|
|
- score_t best_cur_score = MAX_COST;
|
|
|
- int best_prev = 0; // default, in case
|
|
|
+ score_t best_cur_score;
|
|
|
+ int best_prev;
|
|
|
+ score_t cost, score;
|
|
|
|
|
|
- ss_cur[m].score = MAX_COST;
|
|
|
ss_cur[m].costs = costs[n + 1][ctx];
|
|
|
if (level < 0 || level > thresh_level) {
|
|
|
+ ss_cur[m].score = MAX_COST;
|
|
|
// Node is dead.
|
|
|
continue;
|
|
|
}
|
|
@@ -682,18 +686,24 @@ static int TrellisQuantizeBlock(const VP8Encoder* const enc,
|
|
|
}
|
|
|
|
|
|
// Inspect all possible non-dead predecessors. Retain only the best one.
|
|
|
- for (p = -MIN_DELTA; p <= MAX_DELTA; ++p) {
|
|
|
+ // The base_score is added to all scores so it is only added for the final
|
|
|
+ // value after the loop.
|
|
|
+ cost = VP8LevelCost(ss_prev[-MIN_DELTA].costs, level);
|
|
|
+ best_cur_score =
|
|
|
+ ss_prev[-MIN_DELTA].score + RDScoreTrellis(lambda, cost, 0);
|
|
|
+ best_prev = -MIN_DELTA;
|
|
|
+ for (p = -MIN_DELTA + 1; p <= MAX_DELTA; ++p) {
|
|
|
// Dead nodes (with ss_prev[p].score >= MAX_COST) are automatically
|
|
|
// eliminated since their score can't be better than the current best.
|
|
|
- const score_t cost = VP8LevelCost(ss_prev[p].costs, level);
|
|
|
+ cost = VP8LevelCost(ss_prev[p].costs, level);
|
|
|
// Examine node assuming it's a non-terminal one.
|
|
|
- const score_t score =
|
|
|
- base_score + ss_prev[p].score + RDScoreTrellis(lambda, cost, 0);
|
|
|
+ score = ss_prev[p].score + RDScoreTrellis(lambda, cost, 0);
|
|
|
if (score < best_cur_score) {
|
|
|
best_cur_score = score;
|
|
|
best_prev = p;
|
|
|
}
|
|
|
}
|
|
|
+ best_cur_score += base_score;
|
|
|
// Store best finding in current node.
|
|
|
cur->sign = sign;
|
|
|
cur->level = level;
|
|
@@ -701,11 +711,11 @@ static int TrellisQuantizeBlock(const VP8Encoder* const enc,
|
|
|
ss_cur[m].score = best_cur_score;
|
|
|
|
|
|
// Now, record best terminal node (and thus best entry in the graph).
|
|
|
- if (level != 0) {
|
|
|
+ if (level != 0 && best_cur_score < best_score) {
|
|
|
const score_t last_pos_cost =
|
|
|
(n < 15) ? VP8BitCost(0, probas[band][ctx][0]) : 0;
|
|
|
const score_t last_pos_score = RDScoreTrellis(lambda, last_pos_cost, 0);
|
|
|
- const score_t score = best_cur_score + last_pos_score;
|
|
|
+ score = best_cur_score + last_pos_score;
|
|
|
if (score < best_score) {
|
|
|
best_score = score;
|
|
|
best_path[0] = n; // best eob position
|
|
@@ -717,10 +727,16 @@ static int TrellisQuantizeBlock(const VP8Encoder* const enc,
|
|
|
}
|
|
|
|
|
|
// Fresh start
|
|
|
- memset(in + first, 0, (16 - first) * sizeof(*in));
|
|
|
- memset(out + first, 0, (16 - first) * sizeof(*out));
|
|
|
+ // Beware! We must preserve in[0]/out[0] value for TYPE_I16_AC case.
|
|
|
+ if (coeff_type == TYPE_I16_AC) {
|
|
|
+ memset(in + 1, 0, 15 * sizeof(*in));
|
|
|
+ memset(out + 1, 0, 15 * sizeof(*out));
|
|
|
+ } else {
|
|
|
+ memset(in, 0, 16 * sizeof(*in));
|
|
|
+ memset(out, 0, 16 * sizeof(*out));
|
|
|
+ }
|
|
|
if (best_path[0] == -1) {
|
|
|
- return 0; // skip!
|
|
|
+ return 0; // skip!
|
|
|
}
|
|
|
|
|
|
{
|
|
@@ -775,9 +791,9 @@ static int ReconstructIntra16(VP8EncIterator* const it,
|
|
|
for (y = 0, n = 0; y < 4; ++y) {
|
|
|
for (x = 0; x < 4; ++x, ++n) {
|
|
|
const int ctx = it->top_nz_[x] + it->left_nz_[y];
|
|
|
- const int non_zero =
|
|
|
- TrellisQuantizeBlock(enc, tmp[n], rd->y_ac_levels[n], ctx, 0,
|
|
|
- &dqm->y1_, dqm->lambda_trellis_i16_);
|
|
|
+ const int non_zero = TrellisQuantizeBlock(
|
|
|
+ enc, tmp[n], rd->y_ac_levels[n], ctx, TYPE_I16_AC, &dqm->y1_,
|
|
|
+ dqm->lambda_trellis_i16_);
|
|
|
it->top_nz_[x] = it->left_nz_[y] = non_zero;
|
|
|
rd->y_ac_levels[n][0] = 0;
|
|
|
nz |= non_zero << n;
|
|
@@ -818,7 +834,7 @@ static int ReconstructIntra4(VP8EncIterator* const it,
|
|
|
if (DO_TRELLIS_I4 && it->do_trellis_) {
|
|
|
const int x = it->i4_ & 3, y = it->i4_ >> 2;
|
|
|
const int ctx = it->top_nz_[x] + it->left_nz_[y];
|
|
|
- nz = TrellisQuantizeBlock(enc, tmp, levels, ctx, 3, &dqm->y1_,
|
|
|
+ nz = TrellisQuantizeBlock(enc, tmp, levels, ctx, TYPE_I4_AC, &dqm->y1_,
|
|
|
dqm->lambda_trellis_i4_);
|
|
|
} else {
|
|
|
nz = VP8EncQuantizeBlock(tmp, levels, &dqm->y1_);
|
|
@@ -927,9 +943,9 @@ static int ReconstructUV(VP8EncIterator* const it, VP8ModeScore* const rd,
|
|
|
for (y = 0; y < 2; ++y) {
|
|
|
for (x = 0; x < 2; ++x, ++n) {
|
|
|
const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y];
|
|
|
- const int non_zero =
|
|
|
- TrellisQuantizeBlock(enc, tmp[n], rd->uv_levels[n], ctx, 2,
|
|
|
- &dqm->uv_, dqm->lambda_trellis_uv_);
|
|
|
+ const int non_zero = TrellisQuantizeBlock(
|
|
|
+ enc, tmp[n], rd->uv_levels[n], ctx, TYPE_CHROMA_A, &dqm->uv_,
|
|
|
+ dqm->lambda_trellis_uv_);
|
|
|
it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = non_zero;
|
|
|
nz |= non_zero << n;
|
|
|
}
|