mirror of
https://github.com/webmproject/libwebp.git
synced 2024-11-19 20:08:28 +01:00
Convert predictor_enc.c to fixed point
Also remove the last float in histogram_enc.c Change-Id: I6f647a5fc6dd34a19292820817472b4462c94f49
This commit is contained in:
parent
94de6c7fed
commit
2e81017c7a
@ -1247,9 +1247,10 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
|
|||||||
// Don't combine the histograms using stochastic and greedy heuristics for
|
// Don't combine the histograms using stochastic and greedy heuristics for
|
||||||
// low-effort compression mode.
|
// low-effort compression mode.
|
||||||
if (!low_effort || !entropy_combine) {
|
if (!low_effort || !entropy_combine) {
|
||||||
const float x = quality / 100.f;
|
|
||||||
// cubic ramp between 1 and MAX_HISTO_GREEDY:
|
// cubic ramp between 1 and MAX_HISTO_GREEDY:
|
||||||
const int threshold_size = (int)(1 + (x * x * x) * (MAX_HISTO_GREEDY - 1));
|
const int threshold_size =
|
||||||
|
(int)(1 + DivRound(quality * quality * quality * (MAX_HISTO_GREEDY - 1),
|
||||||
|
100 * 100 * 100));
|
||||||
int do_greedy;
|
int do_greedy;
|
||||||
if (!HistogramCombineStochastic(image_histo, &num_used, threshold_size,
|
if (!HistogramCombineStochastic(image_histo, &num_used, threshold_size,
|
||||||
&do_greedy)) {
|
&do_greedy)) {
|
||||||
|
@ -21,9 +21,8 @@
|
|||||||
#include "src/enc/vp8i_enc.h"
|
#include "src/enc/vp8i_enc.h"
|
||||||
#include "src/enc/vp8li_enc.h"
|
#include "src/enc/vp8li_enc.h"
|
||||||
|
|
||||||
#define MAX_DIFF_COST (1e30f)
|
|
||||||
#define HISTO_SIZE (4 * 256)
|
#define HISTO_SIZE (4 * 256)
|
||||||
static const float kSpatialPredictorBias = 15.f;
|
static const int64_t kSpatialPredictorBias = 15ll << LOG_2_PRECISION_BITS;
|
||||||
static const int kPredLowEffort = 11;
|
static const int kPredLowEffort = 11;
|
||||||
static const uint32_t kMaskAlpha = 0xff000000;
|
static const uint32_t kMaskAlpha = 0xff000000;
|
||||||
|
|
||||||
@ -35,33 +34,34 @@ static WEBP_INLINE int GetMin(int a, int b) { return (a > b) ? b : a; }
|
|||||||
|
|
||||||
// Compute a bias for prediction entropy using a global heuristic to favor
|
// Compute a bias for prediction entropy using a global heuristic to favor
|
||||||
// values closer to 0. Hence the final negative sign.
|
// values closer to 0. Hence the final negative sign.
|
||||||
static float PredictionCostBias(const uint32_t counts[256], int weight_0,
|
// 'exp_val' has a scaling factor of 1/100.
|
||||||
float exp_val) {
|
static int64_t PredictionCostBias(const uint32_t counts[256], uint64_t weight_0,
|
||||||
|
uint64_t exp_val) {
|
||||||
const int significant_symbols = 256 >> 4;
|
const int significant_symbols = 256 >> 4;
|
||||||
const float exp_decay_factor = 0.6f;
|
const uint64_t exp_decay_factor = 6; // has a scaling factor of 1/10
|
||||||
float bits = (float)weight_0 * counts[0];
|
uint64_t bits = (weight_0 * counts[0]) << LOG_2_PRECISION_BITS;
|
||||||
int i;
|
int i;
|
||||||
|
exp_val <<= LOG_2_PRECISION_BITS;
|
||||||
for (i = 1; i < significant_symbols; ++i) {
|
for (i = 1; i < significant_symbols; ++i) {
|
||||||
bits += exp_val * (counts[i] + counts[256 - i]);
|
bits += DivRound(exp_val * (counts[i] + counts[256 - i]), 100);
|
||||||
exp_val *= exp_decay_factor;
|
exp_val = DivRound(exp_decay_factor * exp_val, 10);
|
||||||
}
|
}
|
||||||
return (float)(-0.1 * bits);
|
return -DivRound((int64_t)bits, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
static float PredictionCostSpatialHistogram(
|
static int64_t PredictionCostSpatialHistogram(
|
||||||
const uint32_t accumulated[HISTO_SIZE], const uint32_t tile[HISTO_SIZE],
|
const uint32_t accumulated[HISTO_SIZE], const uint32_t tile[HISTO_SIZE],
|
||||||
int mode, int left_mode, int above_mode) {
|
int mode, int left_mode, int above_mode) {
|
||||||
int i;
|
int i;
|
||||||
float retval = 0.f;
|
int64_t retval = 0;
|
||||||
for (i = 0; i < 4; ++i) {
|
for (i = 0; i < 4; ++i) {
|
||||||
const float kExpValue = 0.94f;
|
const uint64_t kExpValue = 94;
|
||||||
retval += PredictionCostBias(&tile[i * 256], 1, kExpValue);
|
retval += PredictionCostBias(&tile[i * 256], 1, kExpValue);
|
||||||
// Compute the new cost if 'tile' is added to 'accumulate' but also add the
|
// Compute the new cost if 'tile' is added to 'accumulate' but also add the
|
||||||
// cost of the current histogram to guide the spatial predictor selection.
|
// cost of the current histogram to guide the spatial predictor selection.
|
||||||
// Basically, favor low entropy, locally and globally.
|
// Basically, favor low entropy, locally and globally.
|
||||||
retval += (float)VP8LCombinedShannonEntropy(&tile[i * 256],
|
retval += (int64_t)VP8LCombinedShannonEntropy(&tile[i * 256],
|
||||||
&accumulated[i * 256]) /
|
&accumulated[i * 256]);
|
||||||
(1ll << LOG_2_PRECISION_BITS);
|
|
||||||
}
|
}
|
||||||
// Favor keeping the areas locally similar.
|
// Favor keeping the areas locally similar.
|
||||||
if (mode == left_mode) retval -= kSpatialPredictorBias;
|
if (mode == left_mode) retval -= kSpatialPredictorBias;
|
||||||
@ -341,7 +341,7 @@ static int GetBestPredictorForTile(
|
|||||||
uint32_t* upper_row = argb_scratch;
|
uint32_t* upper_row = argb_scratch;
|
||||||
uint32_t* current_row = upper_row + width + 1;
|
uint32_t* current_row = upper_row + width + 1;
|
||||||
uint8_t* const max_diffs = (uint8_t*)(current_row + width + 1);
|
uint8_t* const max_diffs = (uint8_t*)(current_row + width + 1);
|
||||||
float best_diff = MAX_DIFF_COST;
|
int64_t best_diff = WEBP_INT64_MAX;
|
||||||
int best_mode = 0;
|
int best_mode = 0;
|
||||||
int mode;
|
int mode;
|
||||||
uint32_t histo_stack_1[HISTO_SIZE];
|
uint32_t histo_stack_1[HISTO_SIZE];
|
||||||
@ -354,7 +354,7 @@ static int GetBestPredictorForTile(
|
|||||||
assert(max_x <= (1 << MAX_TRANSFORM_BITS));
|
assert(max_x <= (1 << MAX_TRANSFORM_BITS));
|
||||||
|
|
||||||
for (mode = 0; mode < kNumPredModes; ++mode) {
|
for (mode = 0; mode < kNumPredModes; ++mode) {
|
||||||
float cur_diff;
|
int64_t cur_diff;
|
||||||
int relative_y;
|
int relative_y;
|
||||||
memset(histo_argb, 0, sizeof(histo_stack_1));
|
memset(histo_argb, 0, sizeof(histo_stack_1));
|
||||||
if (start_y > 0) {
|
if (start_y > 0) {
|
||||||
@ -607,35 +607,36 @@ static WEBP_INLINE uint32_t MultipliersToColorCode(
|
|||||||
m->green_to_red_;
|
m->green_to_red_;
|
||||||
}
|
}
|
||||||
|
|
||||||
static float PredictionCostCrossColor(const uint32_t accumulated[256],
|
static int64_t PredictionCostCrossColor(const uint32_t accumulated[256],
|
||||||
const uint32_t counts[256]) {
|
const uint32_t counts[256]) {
|
||||||
// Favor low entropy, locally and globally.
|
// Favor low entropy, locally and globally.
|
||||||
// Favor small absolute values for PredictionCostSpatial
|
// Favor small absolute values for PredictionCostSpatial
|
||||||
static const float kExpValue = 2.4f;
|
static const uint64_t kExpValue = 240;
|
||||||
return (float)VP8LCombinedShannonEntropy(counts, accumulated) /
|
return (int64_t)VP8LCombinedShannonEntropy(counts, accumulated) +
|
||||||
(1ll << LOG_2_PRECISION_BITS) +
|
|
||||||
PredictionCostBias(counts, 3, kExpValue);
|
PredictionCostBias(counts, 3, kExpValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
static float GetPredictionCostCrossColorRed(
|
static int64_t GetPredictionCostCrossColorRed(
|
||||||
const uint32_t* argb, int stride, int tile_width, int tile_height,
|
const uint32_t* argb, int stride, int tile_width, int tile_height,
|
||||||
VP8LMultipliers prev_x, VP8LMultipliers prev_y, int green_to_red,
|
VP8LMultipliers prev_x, VP8LMultipliers prev_y, int green_to_red,
|
||||||
const uint32_t accumulated_red_histo[256]) {
|
const uint32_t accumulated_red_histo[256]) {
|
||||||
uint32_t histo[256] = { 0 };
|
uint32_t histo[256] = { 0 };
|
||||||
float cur_diff;
|
int64_t cur_diff;
|
||||||
|
|
||||||
VP8LCollectColorRedTransforms(argb, stride, tile_width, tile_height,
|
VP8LCollectColorRedTransforms(argb, stride, tile_width, tile_height,
|
||||||
green_to_red, histo);
|
green_to_red, histo);
|
||||||
|
|
||||||
cur_diff = PredictionCostCrossColor(accumulated_red_histo, histo);
|
cur_diff = PredictionCostCrossColor(accumulated_red_histo, histo);
|
||||||
if ((uint8_t)green_to_red == prev_x.green_to_red_) {
|
if ((uint8_t)green_to_red == prev_x.green_to_red_) {
|
||||||
cur_diff -= 3; // favor keeping the areas locally similar
|
// favor keeping the areas locally similar
|
||||||
|
cur_diff -= 3ll << LOG_2_PRECISION_BITS;
|
||||||
}
|
}
|
||||||
if ((uint8_t)green_to_red == prev_y.green_to_red_) {
|
if ((uint8_t)green_to_red == prev_y.green_to_red_) {
|
||||||
cur_diff -= 3; // favor keeping the areas locally similar
|
// favor keeping the areas locally similar
|
||||||
|
cur_diff -= 3ll << LOG_2_PRECISION_BITS;
|
||||||
}
|
}
|
||||||
if (green_to_red == 0) {
|
if (green_to_red == 0) {
|
||||||
cur_diff -= 3;
|
cur_diff -= 3ll << LOG_2_PRECISION_BITS;
|
||||||
}
|
}
|
||||||
return cur_diff;
|
return cur_diff;
|
||||||
}
|
}
|
||||||
@ -648,9 +649,9 @@ static void GetBestGreenToRed(const uint32_t* argb, int stride, int tile_width,
|
|||||||
const int kMaxIters = 4 + ((7 * quality) >> 8); // in range [4..6]
|
const int kMaxIters = 4 + ((7 * quality) >> 8); // in range [4..6]
|
||||||
int green_to_red_best = 0;
|
int green_to_red_best = 0;
|
||||||
int iter, offset;
|
int iter, offset;
|
||||||
float best_diff = GetPredictionCostCrossColorRed(
|
int64_t best_diff = GetPredictionCostCrossColorRed(
|
||||||
argb, stride, tile_width, tile_height, prev_x, prev_y,
|
argb, stride, tile_width, tile_height, prev_x, prev_y, green_to_red_best,
|
||||||
green_to_red_best, accumulated_red_histo);
|
accumulated_red_histo);
|
||||||
for (iter = 0; iter < kMaxIters; ++iter) {
|
for (iter = 0; iter < kMaxIters; ++iter) {
|
||||||
// ColorTransformDelta is a 3.5 bit fixed point, so 32 is equal to
|
// ColorTransformDelta is a 3.5 bit fixed point, so 32 is equal to
|
||||||
// one in color computation. Having initial delta here as 1 is sufficient
|
// one in color computation. Having initial delta here as 1 is sufficient
|
||||||
@ -659,7 +660,7 @@ static void GetBestGreenToRed(const uint32_t* argb, int stride, int tile_width,
|
|||||||
// Try a negative and a positive delta from the best known value.
|
// Try a negative and a positive delta from the best known value.
|
||||||
for (offset = -delta; offset <= delta; offset += 2 * delta) {
|
for (offset = -delta; offset <= delta; offset += 2 * delta) {
|
||||||
const int green_to_red_cur = offset + green_to_red_best;
|
const int green_to_red_cur = offset + green_to_red_best;
|
||||||
const float cur_diff = GetPredictionCostCrossColorRed(
|
const int64_t cur_diff = GetPredictionCostCrossColorRed(
|
||||||
argb, stride, tile_width, tile_height, prev_x, prev_y,
|
argb, stride, tile_width, tile_height, prev_x, prev_y,
|
||||||
green_to_red_cur, accumulated_red_histo);
|
green_to_red_cur, accumulated_red_histo);
|
||||||
if (cur_diff < best_diff) {
|
if (cur_diff < best_diff) {
|
||||||
@ -671,34 +672,38 @@ static void GetBestGreenToRed(const uint32_t* argb, int stride, int tile_width,
|
|||||||
best_tx->green_to_red_ = (green_to_red_best & 0xff);
|
best_tx->green_to_red_ = (green_to_red_best & 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
static float GetPredictionCostCrossColorBlue(
|
static int64_t GetPredictionCostCrossColorBlue(
|
||||||
const uint32_t* argb, int stride, int tile_width, int tile_height,
|
const uint32_t* argb, int stride, int tile_width, int tile_height,
|
||||||
VP8LMultipliers prev_x, VP8LMultipliers prev_y, int green_to_blue,
|
VP8LMultipliers prev_x, VP8LMultipliers prev_y, int green_to_blue,
|
||||||
int red_to_blue, const uint32_t accumulated_blue_histo[256]) {
|
int red_to_blue, const uint32_t accumulated_blue_histo[256]) {
|
||||||
uint32_t histo[256] = { 0 };
|
uint32_t histo[256] = { 0 };
|
||||||
float cur_diff;
|
int64_t cur_diff;
|
||||||
|
|
||||||
VP8LCollectColorBlueTransforms(argb, stride, tile_width, tile_height,
|
VP8LCollectColorBlueTransforms(argb, stride, tile_width, tile_height,
|
||||||
green_to_blue, red_to_blue, histo);
|
green_to_blue, red_to_blue, histo);
|
||||||
|
|
||||||
cur_diff = PredictionCostCrossColor(accumulated_blue_histo, histo);
|
cur_diff = PredictionCostCrossColor(accumulated_blue_histo, histo);
|
||||||
if ((uint8_t)green_to_blue == prev_x.green_to_blue_) {
|
if ((uint8_t)green_to_blue == prev_x.green_to_blue_) {
|
||||||
cur_diff -= 3; // favor keeping the areas locally similar
|
// favor keeping the areas locally similar
|
||||||
|
cur_diff -= 3ll << LOG_2_PRECISION_BITS;
|
||||||
}
|
}
|
||||||
if ((uint8_t)green_to_blue == prev_y.green_to_blue_) {
|
if ((uint8_t)green_to_blue == prev_y.green_to_blue_) {
|
||||||
cur_diff -= 3; // favor keeping the areas locally similar
|
// favor keeping the areas locally similar
|
||||||
|
cur_diff -= 3ll << LOG_2_PRECISION_BITS;
|
||||||
}
|
}
|
||||||
if ((uint8_t)red_to_blue == prev_x.red_to_blue_) {
|
if ((uint8_t)red_to_blue == prev_x.red_to_blue_) {
|
||||||
cur_diff -= 3; // favor keeping the areas locally similar
|
// favor keeping the areas locally similar
|
||||||
|
cur_diff -= 3ll << LOG_2_PRECISION_BITS;
|
||||||
}
|
}
|
||||||
if ((uint8_t)red_to_blue == prev_y.red_to_blue_) {
|
if ((uint8_t)red_to_blue == prev_y.red_to_blue_) {
|
||||||
cur_diff -= 3; // favor keeping the areas locally similar
|
// favor keeping the areas locally similar
|
||||||
|
cur_diff -= 3ll << LOG_2_PRECISION_BITS;
|
||||||
}
|
}
|
||||||
if (green_to_blue == 0) {
|
if (green_to_blue == 0) {
|
||||||
cur_diff -= 3;
|
cur_diff -= 3ll << LOG_2_PRECISION_BITS;
|
||||||
}
|
}
|
||||||
if (red_to_blue == 0) {
|
if (red_to_blue == 0) {
|
||||||
cur_diff -= 3;
|
cur_diff -= 3ll << LOG_2_PRECISION_BITS;
|
||||||
}
|
}
|
||||||
return cur_diff;
|
return cur_diff;
|
||||||
}
|
}
|
||||||
@ -720,9 +725,9 @@ static void GetBestGreenRedToBlue(const uint32_t* argb, int stride,
|
|||||||
int red_to_blue_best = 0;
|
int red_to_blue_best = 0;
|
||||||
int iter;
|
int iter;
|
||||||
// Initial value at origin:
|
// Initial value at origin:
|
||||||
float best_diff = GetPredictionCostCrossColorBlue(
|
int64_t best_diff = GetPredictionCostCrossColorBlue(
|
||||||
argb, stride, tile_width, tile_height, prev_x, prev_y,
|
argb, stride, tile_width, tile_height, prev_x, prev_y, green_to_blue_best,
|
||||||
green_to_blue_best, red_to_blue_best, accumulated_blue_histo);
|
red_to_blue_best, accumulated_blue_histo);
|
||||||
for (iter = 0; iter < iters; ++iter) {
|
for (iter = 0; iter < iters; ++iter) {
|
||||||
const int delta = delta_lut[iter];
|
const int delta = delta_lut[iter];
|
||||||
int axis;
|
int axis;
|
||||||
@ -730,7 +735,7 @@ static void GetBestGreenRedToBlue(const uint32_t* argb, int stride,
|
|||||||
const int green_to_blue_cur =
|
const int green_to_blue_cur =
|
||||||
offset[axis][0] * delta + green_to_blue_best;
|
offset[axis][0] * delta + green_to_blue_best;
|
||||||
const int red_to_blue_cur = offset[axis][1] * delta + red_to_blue_best;
|
const int red_to_blue_cur = offset[axis][1] * delta + red_to_blue_best;
|
||||||
const float cur_diff = GetPredictionCostCrossColorBlue(
|
const int64_t cur_diff = GetPredictionCostCrossColorBlue(
|
||||||
argb, stride, tile_width, tile_height, prev_x, prev_y,
|
argb, stride, tile_width, tile_height, prev_x, prev_y,
|
||||||
green_to_blue_cur, red_to_blue_cur, accumulated_blue_histo);
|
green_to_blue_cur, red_to_blue_cur, accumulated_blue_histo);
|
||||||
if (cur_diff < best_diff) {
|
if (cur_diff < best_diff) {
|
||||||
|
Loading…
Reference in New Issue
Block a user