fast auto-determined filtering strength

kLevelsFromDelta[sharpness][delta] is an inverse look-up table
that tells the minimum filtering strength needed to trigger the
filtering of a step with amplitude 'delta'. We use this table
in various situations:

a) when computing the initial (/global) filtering
strength for each segment. We look at the quantization
step and deduce the proper filtering strength needed
to result this quantization noise (talking the -f option
into account).

b) during intra16 calculation, when a block ends up
very empty (only DC coeffs are non-zero, all ACs have
vanished). We'll rely on the in-loop filtering to
restore the smoothness (if the source was gradient-like
smooth. That's why we look at the distortion too before
triggering the filtering).

Step b) goes _in addition_ to a), potentially raising
the filtering strength if blockiness is likely.

Change-Id: Icaeca93ef21da195b079e6587a44d9edfc8e9efa
This commit is contained in:
skal
2013-10-29 20:13:29 +01:00
parent 43148b6cd2
commit f8bfd5cd1e
4 changed files with 122 additions and 26 deletions

View File

@ -11,12 +11,58 @@
//
// Author: somnath@google.com (Somnath Banerjee)
#include <assert.h>
#include "./vp8enci.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
// this table gives, for a given sharpness, the filtering strength to be
// used (at least) in order to filter a given edge step delta.
#define MAX_DELTA_SIZE 64
static const uint8_t kLevelsFromDelta[8][MAX_DELTA_SIZE] = {
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63 },
{ 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 17, 18,
20, 21, 23, 24, 26, 27, 29, 30, 32, 33, 35, 36, 38, 39, 41, 42,
44, 45, 47, 48, 50, 51, 53, 54, 56, 57, 59, 60, 62, 63, 63, 63,
63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 },
{ 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 14, 16, 17, 19,
20, 22, 23, 25, 26, 28, 29, 31, 32, 34, 35, 37, 38, 40, 41, 43,
44, 46, 47, 49, 50, 52, 53, 55, 56, 58, 59, 61, 62, 63, 63, 63,
63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 },
{ 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 15, 16, 18, 19,
21, 22, 24, 25, 27, 28, 30, 31, 33, 34, 36, 37, 39, 40, 42, 43,
45, 46, 48, 49, 51, 52, 54, 55, 57, 58, 60, 61, 63, 63, 63, 63,
63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 },
{ 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 14, 15, 17, 18, 20,
21, 23, 24, 26, 27, 29, 30, 32, 33, 35, 36, 38, 39, 41, 42, 44,
45, 47, 48, 50, 51, 53, 54, 56, 57, 59, 60, 62, 63, 63, 63, 63,
63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 },
{ 0, 1, 2, 4, 5, 7, 8, 9, 11, 12, 13, 15, 16, 17, 19, 20,
22, 23, 25, 26, 28, 29, 31, 32, 34, 35, 37, 38, 40, 41, 43, 44,
46, 47, 49, 50, 52, 53, 55, 56, 58, 59, 61, 62, 63, 63, 63, 63,
63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 },
{ 0, 1, 2, 4, 5, 7, 8, 9, 11, 12, 13, 15, 16, 18, 19, 21,
22, 24, 25, 27, 28, 30, 31, 33, 34, 36, 37, 39, 40, 42, 43, 45,
46, 48, 49, 51, 52, 54, 55, 57, 58, 60, 61, 63, 63, 63, 63, 63,
63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 },
{ 0, 1, 2, 4, 5, 7, 8, 9, 11, 12, 14, 15, 17, 18, 20, 21,
23, 24, 26, 27, 29, 30, 32, 33, 35, 36, 38, 39, 41, 42, 44, 45,
47, 48, 50, 51, 53, 54, 56, 57, 59, 60, 62, 63, 63, 63, 63, 63,
63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 }
};
int VP8FilterStrengthFromDelta(int sharpness, int delta) {
const int pos = (delta < MAX_DELTA_SIZE) ? delta : MAX_DELTA_SIZE - 1;
assert(sharpness >= 0 && sharpness <= 7);
return kLevelsFromDelta[sharpness][pos];
}
// -----------------------------------------------------------------------------
// NOTE: clip1, tables and InitTables are repeated entries of dsp.c
static uint8_t abs0[255 + 255 + 1]; // abs(i)
static uint8_t abs1[255 + 255 + 1]; // abs(i)>>1
@ -353,12 +399,13 @@ void VP8InitFilter(VP8EncIterator* const it) {
void VP8StoreFilterStats(VP8EncIterator* const it) {
int d;
VP8Encoder* const enc = it->enc_;
const int s = it->mb_->segment_;
const int level0 = it->enc_->dqm_[s].fstrength_; // TODO: ref_lf_delta[]
const int level0 = enc->dqm_[s].fstrength_; // TODO: ref_lf_delta[]
// explore +/-quant range of values around level0
const int delta_min = -it->enc_->dqm_[s].quant_;
const int delta_max = it->enc_->dqm_[s].quant_;
const int delta_min = -enc->dqm_[s].quant_;
const int delta_max = enc->dqm_[s].quant_;
const int step_size = (delta_max - delta_min >= 4) ? 4 : 1;
if (it->lf_stats_ == NULL) return;
@ -385,9 +432,9 @@ void VP8StoreFilterStats(VP8EncIterator* const it) {
}
void VP8AdjustFilterStrength(VP8EncIterator* const it) {
VP8Encoder* const enc = it->enc_;
if (it->lf_stats_ != NULL) {
int s;
VP8Encoder* const enc = it->enc_;
for (s = 0; s < NUM_MB_SEGMENTS; s++) {
int i, best_level = 0;
// Improvement over filter level 0 should be at least 1e-5 (relatively)
@ -401,9 +448,28 @@ void VP8AdjustFilterStrength(VP8EncIterator* const it) {
}
enc->dqm_[s].fstrength_ = best_level;
}
} else if (enc->config_->filter_strength > 0) {
int max_level = 0;
int s;
for (s = 0; s < NUM_MB_SEGMENTS; s++) {
VP8SegmentInfo* const dqm = &enc->dqm_[s];
// this '>> 3' accounts for some inverse WHT scaling
const int delta = (dqm->max_edge_ * dqm->y2_.q_[1]) >> 3;
const int level =
VP8FilterStrengthFromDelta(enc->filter_hdr_.sharpness_, delta);
if (level > dqm->fstrength_) {
dqm->fstrength_ = level;
}
if (max_level < dqm->fstrength_) {
max_level = dqm->fstrength_;
}
}
enc->filter_hdr_.level_ = max_level;
}
}
// -----------------------------------------------------------------------------
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif