mirror of
https://github.com/webmproject/libwebp.git
synced 2024-11-20 04:18:26 +01:00
Merge "Refactor GetBestPredictorForTile for future tuning."
This commit is contained in:
commit
e3dd9243cb
@ -541,15 +541,14 @@ static const PredictorFunc kPredictors[16] = {
|
|||||||
Predictor0, Predictor0 // <- padding security sentinels
|
Predictor0, Predictor0 // <- padding security sentinels
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO(vikasa): Replace 256 etc with defines.
|
static float PredictionCostSpatial(const int* const counts, int weight_0,
|
||||||
static float PredictionCostSpatial(const int* counts,
|
double exp_val, int n) {
|
||||||
int weight_0, double exp_val) {
|
const int significant_symbols = n >> 4;
|
||||||
const int significant_symbols = 16;
|
|
||||||
const double exp_decay_factor = 0.6;
|
const double exp_decay_factor = 0.6;
|
||||||
double bits = weight_0 * counts[0];
|
double bits = weight_0 * counts[0];
|
||||||
int i;
|
int i;
|
||||||
for (i = 1; i < significant_symbols; ++i) {
|
for (i = 1; i < significant_symbols; ++i) {
|
||||||
bits += exp_val * (counts[i] + counts[256 - i]);
|
bits += exp_val * (counts[i] + counts[n - i]);
|
||||||
exp_val *= exp_decay_factor;
|
exp_val *= exp_decay_factor;
|
||||||
}
|
}
|
||||||
return (float)(-0.1 * bits);
|
return (float)(-0.1 * bits);
|
||||||
@ -563,12 +562,13 @@ static float CombinedShannonEntropy(const int* const X,
|
|||||||
int sumX = 0, sumXY = 0;
|
int sumX = 0, sumXY = 0;
|
||||||
for (i = 0; i < n; ++i) {
|
for (i = 0; i < n; ++i) {
|
||||||
const int x = X[i];
|
const int x = X[i];
|
||||||
const int xy = X[i] + Y[i];
|
const int xy = x + Y[i];
|
||||||
if (x != 0) {
|
if (x != 0) {
|
||||||
sumX += x;
|
sumX += x;
|
||||||
retval -= VP8LFastSLog2(x);
|
retval -= VP8LFastSLog2(x);
|
||||||
}
|
sumXY += xy;
|
||||||
if (xy != 0) {
|
retval -= VP8LFastSLog2(xy);
|
||||||
|
} else if (xy != 0) {
|
||||||
sumXY += xy;
|
sumXY += xy;
|
||||||
retval -= VP8LFastSLog2(xy);
|
retval -= VP8LFastSLog2(xy);
|
||||||
}
|
}
|
||||||
@ -577,48 +577,53 @@ static float CombinedShannonEntropy(const int* const X,
|
|||||||
return (float)retval;
|
return (float)retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static float PredictionCostSpatialHistogram(int accumulated[4][256],
|
static float PredictionCostSpatialHistogram(const int accumulated[4][256],
|
||||||
int tile[4][256]) {
|
const int tile[4][256]) {
|
||||||
int i;
|
int i;
|
||||||
double retval = 0;
|
double retval = 0;
|
||||||
for (i = 0; i < 4; ++i) {
|
for (i = 0; i < 4; ++i) {
|
||||||
const double kExpValue = 0.94;
|
const double kExpValue = 0.94;
|
||||||
retval += PredictionCostSpatial(tile[i], 1, kExpValue);
|
retval += PredictionCostSpatial(tile[i], 1, kExpValue, 256);
|
||||||
retval += CombinedShannonEntropy(tile[i], accumulated[i], 256);
|
retval += CombinedShannonEntropy(tile[i], accumulated[i], 256);
|
||||||
}
|
}
|
||||||
return (float)retval;
|
return (float)retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static WEBP_INLINE void UpdateHisto(int histo_argb[4][256], uint32_t argb) {
|
||||||
|
++histo_argb[0][argb >> 24];
|
||||||
|
++histo_argb[1][(argb >> 16) & 0xff];
|
||||||
|
++histo_argb[2][(argb >> 8) & 0xff];
|
||||||
|
++histo_argb[3][argb & 0xff];
|
||||||
|
}
|
||||||
|
|
||||||
static int GetBestPredictorForTile(int width, int height,
|
static int GetBestPredictorForTile(int width, int height,
|
||||||
int tile_x, int tile_y, int bits,
|
int tile_x, int tile_y, int bits,
|
||||||
int accumulated[4][256],
|
const int accumulated[4][256],
|
||||||
const uint32_t* const argb_scratch) {
|
const uint32_t* const argb_scratch) {
|
||||||
const int kNumPredModes = 14;
|
const int kNumPredModes = 14;
|
||||||
const int col_start = tile_x << bits;
|
const int col_start = tile_x << bits;
|
||||||
const int row_start = tile_y << bits;
|
const int row_start = tile_y << bits;
|
||||||
const int tile_size = 1 << bits;
|
const int tile_size = 1 << bits;
|
||||||
const int ymax = GetMin(tile_size, height - row_start);
|
const int max_y = GetMin(tile_size, height - row_start);
|
||||||
const int xmax = GetMin(tile_size, width - col_start);
|
const int max_x = GetMin(tile_size, width - col_start);
|
||||||
int histo[4][256];
|
|
||||||
float best_diff = MAX_DIFF_COST;
|
float best_diff = MAX_DIFF_COST;
|
||||||
int best_mode = 0;
|
int best_mode = 0;
|
||||||
|
|
||||||
int mode;
|
int mode;
|
||||||
for (mode = 0; mode < kNumPredModes; ++mode) {
|
for (mode = 0; mode < kNumPredModes; ++mode) {
|
||||||
const uint32_t* current_row = argb_scratch;
|
const uint32_t* current_row = argb_scratch;
|
||||||
const PredictorFunc pred_func = kPredictors[mode];
|
const PredictorFunc pred_func = kPredictors[mode];
|
||||||
float cur_diff;
|
float cur_diff;
|
||||||
int y;
|
int y;
|
||||||
memset(&histo[0][0], 0, sizeof(histo));
|
int histo_argb[4][256];
|
||||||
for (y = 0; y < ymax; ++y) {
|
memset(histo_argb, 0, sizeof(histo_argb));
|
||||||
|
for (y = 0; y < max_y; ++y) {
|
||||||
int x;
|
int x;
|
||||||
const int row = row_start + y;
|
const int row = row_start + y;
|
||||||
const uint32_t* const upper_row = current_row;
|
const uint32_t* const upper_row = current_row;
|
||||||
current_row = upper_row + width;
|
current_row = upper_row + width;
|
||||||
for (x = 0; x < xmax; ++x) {
|
for (x = 0; x < max_x; ++x) {
|
||||||
const int col = col_start + x;
|
const int col = col_start + x;
|
||||||
uint32_t predict;
|
uint32_t predict;
|
||||||
uint32_t predict_diff;
|
|
||||||
if (row == 0) {
|
if (row == 0) {
|
||||||
predict = (col == 0) ? ARGB_BLACK : current_row[col - 1]; // Left.
|
predict = (col == 0) ? ARGB_BLACK : current_row[col - 1]; // Left.
|
||||||
} else if (col == 0) {
|
} else if (col == 0) {
|
||||||
@ -626,14 +631,11 @@ static int GetBestPredictorForTile(int width, int height,
|
|||||||
} else {
|
} else {
|
||||||
predict = pred_func(current_row[col - 1], upper_row + col);
|
predict = pred_func(current_row[col - 1], upper_row + col);
|
||||||
}
|
}
|
||||||
predict_diff = VP8LSubPixels(current_row[col], predict);
|
UpdateHisto(histo_argb, VP8LSubPixels(current_row[col], predict));
|
||||||
++histo[0][predict_diff >> 24];
|
|
||||||
++histo[1][((predict_diff >> 16) & 0xff)];
|
|
||||||
++histo[2][((predict_diff >> 8) & 0xff)];
|
|
||||||
++histo[3][(predict_diff & 0xff)];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cur_diff = PredictionCostSpatialHistogram(accumulated, histo);
|
cur_diff = PredictionCostSpatialHistogram(
|
||||||
|
accumulated, (const int (*)[256])histo_argb);
|
||||||
if (cur_diff < best_diff) {
|
if (cur_diff < best_diff) {
|
||||||
best_diff = cur_diff;
|
best_diff = cur_diff;
|
||||||
best_mode = mode;
|
best_mode = mode;
|
||||||
@ -650,18 +652,18 @@ static void CopyTileWithPrediction(int width, int height,
|
|||||||
const int col_start = tile_x << bits;
|
const int col_start = tile_x << bits;
|
||||||
const int row_start = tile_y << bits;
|
const int row_start = tile_y << bits;
|
||||||
const int tile_size = 1 << bits;
|
const int tile_size = 1 << bits;
|
||||||
const int ymax = GetMin(tile_size, height - row_start);
|
const int max_y = GetMin(tile_size, height - row_start);
|
||||||
const int xmax = GetMin(tile_size, width - col_start);
|
const int max_x = GetMin(tile_size, width - col_start);
|
||||||
const PredictorFunc pred_func = kPredictors[mode];
|
const PredictorFunc pred_func = kPredictors[mode];
|
||||||
const uint32_t* current_row = argb_scratch;
|
const uint32_t* current_row = argb_scratch;
|
||||||
|
|
||||||
int y;
|
int y;
|
||||||
for (y = 0; y < ymax; ++y) {
|
for (y = 0; y < max_y; ++y) {
|
||||||
int x;
|
int x;
|
||||||
const int row = row_start + y;
|
const int row = row_start + y;
|
||||||
const uint32_t* const upper_row = current_row;
|
const uint32_t* const upper_row = current_row;
|
||||||
current_row = upper_row + width;
|
current_row = upper_row + width;
|
||||||
for (x = 0; x < xmax; ++x) {
|
for (x = 0; x < max_x; ++x) {
|
||||||
const int col = col_start + x;
|
const int col = col_start + x;
|
||||||
const int pix = row * width + col;
|
const int pix = row * width + col;
|
||||||
uint32_t predict;
|
uint32_t predict;
|
||||||
@ -707,7 +709,8 @@ void VP8LResidualImage(int width, int height, int bits,
|
|||||||
if (all_x_max > width) {
|
if (all_x_max > width) {
|
||||||
all_x_max = width;
|
all_x_max = width;
|
||||||
}
|
}
|
||||||
pred = GetBestPredictorForTile(width, height, tile_x, tile_y, bits, histo,
|
pred = GetBestPredictorForTile(width, height, tile_x, tile_y, bits,
|
||||||
|
(const int (*)[256])histo,
|
||||||
argb_scratch);
|
argb_scratch);
|
||||||
image[tile_y * tiles_per_row + tile_x] = 0xff000000u | (pred << 8);
|
image[tile_y * tiles_per_row + tile_x] = 0xff000000u | (pred << 8);
|
||||||
CopyTileWithPrediction(width, height, tile_x, tile_y, bits, pred,
|
CopyTileWithPrediction(width, height, tile_x, tile_y, bits, pred,
|
||||||
@ -721,11 +724,7 @@ void VP8LResidualImage(int width, int height, int bits,
|
|||||||
}
|
}
|
||||||
ix = all_y * width + tile_x_offset;
|
ix = all_y * width + tile_x_offset;
|
||||||
for (all_x = tile_x_offset; all_x < all_x_max; ++all_x, ++ix) {
|
for (all_x = tile_x_offset; all_x < all_x_max; ++all_x, ++ix) {
|
||||||
const uint32_t a = argb[ix];
|
UpdateHisto(histo, argb[ix]);
|
||||||
++histo[0][a >> 24];
|
|
||||||
++histo[1][((a >> 16) & 0xff)];
|
|
||||||
++histo[2][((a >> 8) & 0xff)];
|
|
||||||
++histo[3][(a & 0xff)];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -905,13 +904,13 @@ static float PredictionCostCrossColor(const int accumulated[256],
|
|||||||
// Favor small absolute values for PredictionCostSpatial
|
// Favor small absolute values for PredictionCostSpatial
|
||||||
static const double kExpValue = 2.4;
|
static const double kExpValue = 2.4;
|
||||||
return CombinedShannonEntropy(counts, accumulated, 256) +
|
return CombinedShannonEntropy(counts, accumulated, 256) +
|
||||||
PredictionCostSpatial(counts, 3, kExpValue);
|
PredictionCostSpatial(counts, 3, kExpValue, 256);
|
||||||
}
|
}
|
||||||
|
|
||||||
static float GetPredictionCostCrossColorRed(
|
static float GetPredictionCostCrossColorRed(
|
||||||
int tile_x_offset, int tile_y_offset, int all_x_max, int all_y_max,
|
int tile_x_offset, int tile_y_offset, int all_x_max, int all_y_max,
|
||||||
int xsize, Multipliers prev_x, Multipliers prev_y, int green_to_red,
|
int xsize, Multipliers prev_x, Multipliers prev_y, int green_to_red,
|
||||||
const int* const accumulated_red_histo, const uint32_t* const argb) {
|
const int accumulated_red_histo[256], const uint32_t* const argb) {
|
||||||
int all_y;
|
int all_y;
|
||||||
int histo[256] = { 0 };
|
int histo[256] = { 0 };
|
||||||
float cur_diff;
|
float cur_diff;
|
||||||
@ -925,7 +924,7 @@ static float GetPredictionCostCrossColorRed(
|
|||||||
++histo[TransformColorRed(green_to_red, argb[ix])]; // red.
|
++histo[TransformColorRed(green_to_red, argb[ix])]; // red.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cur_diff = PredictionCostCrossColor(&accumulated_red_histo[0], &histo[0]);
|
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
|
cur_diff -= 3; // favor keeping the areas locally similar
|
||||||
}
|
}
|
||||||
@ -941,7 +940,7 @@ static float GetPredictionCostCrossColorRed(
|
|||||||
static void GetBestGreenToRed(
|
static void GetBestGreenToRed(
|
||||||
int tile_x_offset, int tile_y_offset, int all_x_max, int all_y_max,
|
int tile_x_offset, int tile_y_offset, int all_x_max, int all_y_max,
|
||||||
int xsize, Multipliers prev_x, Multipliers prev_y,
|
int xsize, Multipliers prev_x, Multipliers prev_y,
|
||||||
const int* const accumulated_red_histo, const uint32_t* const argb,
|
const int accumulated_red_histo[256], const uint32_t* const argb,
|
||||||
Multipliers* best_tx) {
|
Multipliers* best_tx) {
|
||||||
int min_green_to_red = -64;
|
int min_green_to_red = -64;
|
||||||
int max_green_to_red = 64;
|
int max_green_to_red = 64;
|
||||||
@ -955,13 +954,13 @@ static void GetBestGreenToRed(
|
|||||||
if (eval_min) {
|
if (eval_min) {
|
||||||
cur_diff_min = GetPredictionCostCrossColorRed(
|
cur_diff_min = GetPredictionCostCrossColorRed(
|
||||||
tile_x_offset, tile_y_offset, all_x_max, all_y_max, xsize,
|
tile_x_offset, tile_y_offset, all_x_max, all_y_max, xsize,
|
||||||
prev_x, prev_y, min_green_to_red, &accumulated_red_histo[0], argb);
|
prev_x, prev_y, min_green_to_red, accumulated_red_histo, argb);
|
||||||
eval_min = 0;
|
eval_min = 0;
|
||||||
}
|
}
|
||||||
if (eval_max) {
|
if (eval_max) {
|
||||||
cur_diff_max = GetPredictionCostCrossColorRed(
|
cur_diff_max = GetPredictionCostCrossColorRed(
|
||||||
tile_x_offset, tile_y_offset, all_x_max, all_y_max, xsize,
|
tile_x_offset, tile_y_offset, all_x_max, all_y_max, xsize,
|
||||||
prev_x, prev_y, max_green_to_red, &accumulated_red_histo[0], argb);
|
prev_x, prev_y, max_green_to_red, accumulated_red_histo, argb);
|
||||||
eval_max = 0;
|
eval_max = 0;
|
||||||
}
|
}
|
||||||
if (cur_diff_min < cur_diff_max) {
|
if (cur_diff_min < cur_diff_max) {
|
||||||
@ -980,7 +979,7 @@ static void GetBestGreenToRed(
|
|||||||
static float GetPredictionCostCrossColorBlue(
|
static float GetPredictionCostCrossColorBlue(
|
||||||
int tile_x_offset, int tile_y_offset, int all_x_max, int all_y_max,
|
int tile_x_offset, int tile_y_offset, int all_x_max, int all_y_max,
|
||||||
int xsize, Multipliers prev_x, Multipliers prev_y, int green_to_blue,
|
int xsize, Multipliers prev_x, Multipliers prev_y, int green_to_blue,
|
||||||
int red_to_blue, const int* const accumulated_blue_histo,
|
int red_to_blue, const int accumulated_blue_histo[256],
|
||||||
const uint32_t* const argb) {
|
const uint32_t* const argb) {
|
||||||
int all_y;
|
int all_y;
|
||||||
int histo[256] = { 0 };
|
int histo[256] = { 0 };
|
||||||
@ -995,7 +994,7 @@ static float GetPredictionCostCrossColorBlue(
|
|||||||
++histo[TransformColorBlue(green_to_blue, red_to_blue, argb[ix])];
|
++histo[TransformColorBlue(green_to_blue, red_to_blue, argb[ix])];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cur_diff = PredictionCostCrossColor(&accumulated_blue_histo[0], &histo[0]);
|
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
|
cur_diff -= 3; // favor keeping the areas locally similar
|
||||||
}
|
}
|
||||||
@ -1020,7 +1019,7 @@ static float GetPredictionCostCrossColorBlue(
|
|||||||
static void GetBestGreenRedToBlue(
|
static void GetBestGreenRedToBlue(
|
||||||
int tile_x_offset, int tile_y_offset, int all_x_max, int all_y_max,
|
int tile_x_offset, int tile_y_offset, int all_x_max, int all_y_max,
|
||||||
int xsize, Multipliers prev_x, Multipliers prev_y, int quality,
|
int xsize, Multipliers prev_x, Multipliers prev_y, int quality,
|
||||||
const int* const accumulated_blue_histo, const uint32_t* const argb,
|
const int accumulated_blue_histo[256], const uint32_t* const argb,
|
||||||
Multipliers* best_tx) {
|
Multipliers* best_tx) {
|
||||||
float best_diff = MAX_DIFF_COST;
|
float best_diff = MAX_DIFF_COST;
|
||||||
float cur_diff;
|
float cur_diff;
|
||||||
@ -1048,7 +1047,7 @@ static void GetBestGreenRedToBlue(
|
|||||||
red_to_blue += step) {
|
red_to_blue += step) {
|
||||||
cur_diff = GetPredictionCostCrossColorBlue(
|
cur_diff = GetPredictionCostCrossColorBlue(
|
||||||
tile_x_offset, tile_y_offset, all_x_max, all_y_max, xsize, prev_x,
|
tile_x_offset, tile_y_offset, all_x_max, all_y_max, xsize, prev_x,
|
||||||
prev_y, green_to_blue, red_to_blue, &accumulated_blue_histo[0], argb);
|
prev_y, green_to_blue, red_to_blue, accumulated_blue_histo, argb);
|
||||||
if (cur_diff < best_diff) {
|
if (cur_diff < best_diff) {
|
||||||
best_diff = cur_diff;
|
best_diff = cur_diff;
|
||||||
best_tx->green_to_blue_ = green_to_blue;
|
best_tx->green_to_blue_ = green_to_blue;
|
||||||
@ -1066,8 +1065,8 @@ static Multipliers GetBestColorTransformForTile(
|
|||||||
Multipliers prev_x,
|
Multipliers prev_x,
|
||||||
Multipliers prev_y,
|
Multipliers prev_y,
|
||||||
int quality, int xsize, int ysize,
|
int quality, int xsize, int ysize,
|
||||||
const int* const accumulated_red_histo,
|
const int accumulated_red_histo[256],
|
||||||
const int* const accumulated_blue_histo,
|
const int accumulated_blue_histo[256],
|
||||||
const uint32_t* const argb) {
|
const uint32_t* const argb) {
|
||||||
const int max_tile_size = 1 << bits;
|
const int max_tile_size = 1 << bits;
|
||||||
const int tile_y_offset = tile_y * max_tile_size;
|
const int tile_y_offset = tile_y * max_tile_size;
|
||||||
@ -1078,10 +1077,10 @@ static Multipliers GetBestColorTransformForTile(
|
|||||||
MultipliersClear(&best_tx);
|
MultipliersClear(&best_tx);
|
||||||
|
|
||||||
GetBestGreenToRed(tile_x_offset, tile_y_offset, all_x_max, all_y_max, xsize,
|
GetBestGreenToRed(tile_x_offset, tile_y_offset, all_x_max, all_y_max, xsize,
|
||||||
prev_x, prev_y, &accumulated_red_histo[0], argb, &best_tx);
|
prev_x, prev_y, accumulated_red_histo, argb, &best_tx);
|
||||||
GetBestGreenRedToBlue(tile_x_offset, tile_y_offset, all_x_max, all_y_max,
|
GetBestGreenRedToBlue(tile_x_offset, tile_y_offset, all_x_max, all_y_max,
|
||||||
xsize, prev_x, prev_y, quality,
|
xsize, prev_x, prev_y, quality, accumulated_blue_histo,
|
||||||
&accumulated_blue_histo[0], argb, &best_tx);
|
argb, &best_tx);
|
||||||
return best_tx;
|
return best_tx;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1127,8 +1126,8 @@ void VP8LColorSpaceTransform(int width, int height, int bits, int quality,
|
|||||||
prev_x = GetBestColorTransformForTile(tile_x, tile_y, bits,
|
prev_x = GetBestColorTransformForTile(tile_x, tile_y, bits,
|
||||||
prev_x, prev_y,
|
prev_x, prev_y,
|
||||||
quality, width, height,
|
quality, width, height,
|
||||||
&accumulated_red_histo[0],
|
accumulated_red_histo,
|
||||||
&accumulated_blue_histo[0],
|
accumulated_blue_histo,
|
||||||
argb);
|
argb);
|
||||||
image[offset] = MultipliersToColorCode(&prev_x);
|
image[offset] = MultipliersToColorCode(&prev_x);
|
||||||
CopyTileWithColorTransform(width, height, tile_x_offset, tile_y_offset,
|
CopyTileWithColorTransform(width, height, tile_x_offset, tile_y_offset,
|
||||||
|
Loading…
Reference in New Issue
Block a user