From 206cc1be5a60ea1f66c5bf66608b1597b1ae9698 Mon Sep 17 00:00:00 2001 From: Vikas Arora Date: Wed, 26 Feb 2014 09:47:24 -0800 Subject: [PATCH] Refactor GetBestPredictorForTile for future tuning. This change doesn't impact compression gain or compression speed. Change-Id: Ia87d8a46c6f1ce0f8974178d75a6b0ba0a6e3696 --- src/dsp/lossless.c | 105 ++++++++++++++++++++++----------------------- 1 file changed, 52 insertions(+), 53 deletions(-) diff --git a/src/dsp/lossless.c b/src/dsp/lossless.c index d26c8093..263f61e5 100644 --- a/src/dsp/lossless.c +++ b/src/dsp/lossless.c @@ -541,15 +541,14 @@ static const PredictorFunc kPredictors[16] = { Predictor0, Predictor0 // <- padding security sentinels }; -// TODO(vikasa): Replace 256 etc with defines. -static float PredictionCostSpatial(const int* counts, - int weight_0, double exp_val) { - const int significant_symbols = 16; +static float PredictionCostSpatial(const int* const counts, int weight_0, + double exp_val, int n) { + const int significant_symbols = n >> 4; const double exp_decay_factor = 0.6; double bits = weight_0 * counts[0]; int 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; } return (float)(-0.1 * bits); @@ -563,12 +562,13 @@ static float CombinedShannonEntropy(const int* const X, int sumX = 0, sumXY = 0; for (i = 0; i < n; ++i) { const int x = X[i]; - const int xy = X[i] + Y[i]; + const int xy = x + Y[i]; if (x != 0) { sumX += x; retval -= VP8LFastSLog2(x); - } - if (xy != 0) { + sumXY += xy; + retval -= VP8LFastSLog2(xy); + } else if (xy != 0) { sumXY += xy; retval -= VP8LFastSLog2(xy); } @@ -577,48 +577,53 @@ static float CombinedShannonEntropy(const int* const X, return (float)retval; } -static float PredictionCostSpatialHistogram(int accumulated[4][256], - int tile[4][256]) { +static float PredictionCostSpatialHistogram(const int accumulated[4][256], + const int tile[4][256]) { int i; double retval = 0; for (i = 0; i < 4; ++i) { 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); } 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, int tile_x, int tile_y, int bits, - int accumulated[4][256], + const int accumulated[4][256], const uint32_t* const argb_scratch) { const int kNumPredModes = 14; const int col_start = tile_x << bits; const int row_start = tile_y << bits; const int tile_size = 1 << bits; - const int ymax = GetMin(tile_size, height - row_start); - const int xmax = GetMin(tile_size, width - col_start); - int histo[4][256]; + const int max_y = GetMin(tile_size, height - row_start); + const int max_x = GetMin(tile_size, width - col_start); float best_diff = MAX_DIFF_COST; int best_mode = 0; - int mode; for (mode = 0; mode < kNumPredModes; ++mode) { const uint32_t* current_row = argb_scratch; const PredictorFunc pred_func = kPredictors[mode]; float cur_diff; int y; - memset(&histo[0][0], 0, sizeof(histo)); - for (y = 0; y < ymax; ++y) { + int histo_argb[4][256]; + memset(histo_argb, 0, sizeof(histo_argb)); + for (y = 0; y < max_y; ++y) { int x; const int row = row_start + y; const uint32_t* const upper_row = current_row; current_row = upper_row + width; - for (x = 0; x < xmax; ++x) { + for (x = 0; x < max_x; ++x) { const int col = col_start + x; uint32_t predict; - uint32_t predict_diff; if (row == 0) { predict = (col == 0) ? ARGB_BLACK : current_row[col - 1]; // Left. } else if (col == 0) { @@ -626,14 +631,11 @@ static int GetBestPredictorForTile(int width, int height, } else { predict = pred_func(current_row[col - 1], upper_row + col); } - predict_diff = 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)]; + UpdateHisto(histo_argb, VP8LSubPixels(current_row[col], predict)); } } - cur_diff = PredictionCostSpatialHistogram(accumulated, histo); + cur_diff = PredictionCostSpatialHistogram( + accumulated, (const int (*)[256])histo_argb); if (cur_diff < best_diff) { best_diff = cur_diff; best_mode = mode; @@ -650,18 +652,18 @@ static void CopyTileWithPrediction(int width, int height, const int col_start = tile_x << bits; const int row_start = tile_y << bits; const int tile_size = 1 << bits; - const int ymax = GetMin(tile_size, height - row_start); - const int xmax = GetMin(tile_size, width - col_start); + const int max_y = GetMin(tile_size, height - row_start); + const int max_x = GetMin(tile_size, width - col_start); const PredictorFunc pred_func = kPredictors[mode]; const uint32_t* current_row = argb_scratch; int y; - for (y = 0; y < ymax; ++y) { + for (y = 0; y < max_y; ++y) { int x; const int row = row_start + y; const uint32_t* const upper_row = current_row; 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 pix = row * width + col; uint32_t predict; @@ -707,7 +709,8 @@ void VP8LResidualImage(int width, int height, int bits, if (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); image[tile_y * tiles_per_row + tile_x] = 0xff000000u | (pred << 8); 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; for (all_x = tile_x_offset; all_x < all_x_max; ++all_x, ++ix) { - const uint32_t a = argb[ix]; - ++histo[0][a >> 24]; - ++histo[1][((a >> 16) & 0xff)]; - ++histo[2][((a >> 8) & 0xff)]; - ++histo[3][(a & 0xff)]; + UpdateHisto(histo, argb[ix]); } } } @@ -905,13 +904,13 @@ static float PredictionCostCrossColor(const int accumulated[256], // Favor small absolute values for PredictionCostSpatial static const double kExpValue = 2.4; return CombinedShannonEntropy(counts, accumulated, 256) + - PredictionCostSpatial(counts, 3, kExpValue); + PredictionCostSpatial(counts, 3, kExpValue, 256); } static float GetPredictionCostCrossColorRed( 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, - 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 histo[256] = { 0 }; float cur_diff; @@ -925,7 +924,7 @@ static float GetPredictionCostCrossColorRed( ++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_) { cur_diff -= 3; // favor keeping the areas locally similar } @@ -941,7 +940,7 @@ static float GetPredictionCostCrossColorRed( static void GetBestGreenToRed( int tile_x_offset, int tile_y_offset, int all_x_max, int all_y_max, 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) { int min_green_to_red = -64; int max_green_to_red = 64; @@ -955,13 +954,13 @@ static void GetBestGreenToRed( if (eval_min) { cur_diff_min = GetPredictionCostCrossColorRed( 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; } if (eval_max) { cur_diff_max = GetPredictionCostCrossColorRed( 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; } if (cur_diff_min < cur_diff_max) { @@ -980,7 +979,7 @@ static void GetBestGreenToRed( static float GetPredictionCostCrossColorBlue( 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 red_to_blue, const int* const accumulated_blue_histo, + int red_to_blue, const int accumulated_blue_histo[256], const uint32_t* const argb) { int all_y; int histo[256] = { 0 }; @@ -995,7 +994,7 @@ static float GetPredictionCostCrossColorBlue( ++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_) { cur_diff -= 3; // favor keeping the areas locally similar } @@ -1020,7 +1019,7 @@ static float GetPredictionCostCrossColorBlue( static void GetBestGreenRedToBlue( 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, - 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) { float best_diff = MAX_DIFF_COST; float cur_diff; @@ -1048,7 +1047,7 @@ static void GetBestGreenRedToBlue( red_to_blue += step) { cur_diff = GetPredictionCostCrossColorBlue( 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) { best_diff = cur_diff; best_tx->green_to_blue_ = green_to_blue; @@ -1066,8 +1065,8 @@ static Multipliers GetBestColorTransformForTile( Multipliers prev_x, Multipliers prev_y, int quality, int xsize, int ysize, - const int* const accumulated_red_histo, - const int* const accumulated_blue_histo, + const int accumulated_red_histo[256], + const int accumulated_blue_histo[256], const uint32_t* const argb) { const int max_tile_size = 1 << bits; const int tile_y_offset = tile_y * max_tile_size; @@ -1078,10 +1077,10 @@ static Multipliers GetBestColorTransformForTile( MultipliersClear(&best_tx); 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, - xsize, prev_x, prev_y, quality, - &accumulated_blue_histo[0], argb, &best_tx); + xsize, prev_x, prev_y, quality, accumulated_blue_histo, + argb, &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, prev_y, quality, width, height, - &accumulated_red_histo[0], - &accumulated_blue_histo[0], + accumulated_red_histo, + accumulated_blue_histo, argb); image[offset] = MultipliersToColorCode(&prev_x); CopyTileWithColorTransform(width, height, tile_x_offset, tile_y_offset,