mirror of
https://github.com/webmproject/libwebp.git
synced 2025-02-27 22:32:52 +01:00
Merge "lossless: make prediction in encoder work per scanline"
This commit is contained in:
commit
a7a954c851
@ -598,9 +598,10 @@ static WEBP_INLINE void UpdateHisto(int histo_argb[4][256], uint32_t argb) {
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Returns best predictor and updates the accumulated histogram.
|
||||||
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,
|
||||||
const int accumulated[4][256],
|
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;
|
||||||
@ -611,13 +612,19 @@ static int GetBestPredictorForTile(int width, int height,
|
|||||||
float best_diff = MAX_DIFF_COST;
|
float best_diff = MAX_DIFF_COST;
|
||||||
int best_mode = 0;
|
int best_mode = 0;
|
||||||
int mode;
|
int mode;
|
||||||
|
int histo_stack_1[4][256];
|
||||||
|
int histo_stack_2[4][256];
|
||||||
|
// Need pointers to be able to swap arrays.
|
||||||
|
int (*histo_argb)[256] = histo_stack_1;
|
||||||
|
int (*best_histo)[256] = histo_stack_2;
|
||||||
|
|
||||||
|
int i, j;
|
||||||
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 VP8LPredictorFunc pred_func = VP8LPredictors[mode];
|
const VP8LPredictorFunc pred_func = VP8LPredictors[mode];
|
||||||
float cur_diff;
|
float cur_diff;
|
||||||
int y;
|
int y;
|
||||||
int histo_argb[4][256];
|
memset(histo_argb, 0, sizeof(histo_stack_1));
|
||||||
memset(histo_argb, 0, sizeof(histo_argb));
|
|
||||||
for (y = 0; y < max_y; ++y) {
|
for (y = 0; y < max_y; ++y) {
|
||||||
int x;
|
int x;
|
||||||
const int row = row_start + y;
|
const int row = row_start + y;
|
||||||
@ -637,46 +644,60 @@ static int GetBestPredictorForTile(int width, int height,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
cur_diff = PredictionCostSpatialHistogram(
|
cur_diff = PredictionCostSpatialHistogram(
|
||||||
accumulated, (const int (*)[256])histo_argb);
|
(const int (*)[256])accumulated, (const int (*)[256])histo_argb);
|
||||||
if (cur_diff < best_diff) {
|
if (cur_diff < best_diff) {
|
||||||
|
int (*tmp)[256] = histo_argb;
|
||||||
|
histo_argb = best_histo;
|
||||||
|
best_histo = tmp;
|
||||||
best_diff = cur_diff;
|
best_diff = cur_diff;
|
||||||
best_mode = mode;
|
best_mode = mode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
for (j = 0; j < 256; j++) {
|
||||||
|
accumulated[i][j] += best_histo[i][j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return best_mode;
|
return best_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CopyTileWithPrediction(int width, int height,
|
static void CopyImageWithPrediction(int width, int height,
|
||||||
int tile_x, int tile_y, int bits, int mode,
|
int bits, uint32_t* const modes,
|
||||||
const uint32_t* const argb_scratch,
|
uint32_t* const argb_scratch,
|
||||||
uint32_t* const argb) {
|
uint32_t* const argb) {
|
||||||
const int col_start = tile_x << bits;
|
const int tiles_per_row = VP8LSubSampleSize(width, bits);
|
||||||
const int row_start = tile_y << bits;
|
const int mask = (1 << bits) - 1;
|
||||||
const int tile_size = 1 << bits;
|
// The row size is one pixel longer to allow the top right pixel to point to
|
||||||
const int max_y = GetMin(tile_size, height - row_start);
|
// the leftmost pixel of the next row when at the right edge.
|
||||||
const int max_x = GetMin(tile_size, width - col_start);
|
uint32_t* current_row = argb_scratch;
|
||||||
const VP8LPredictorFunc pred_func = VP8LPredictors[mode];
|
uint32_t* upper_row = argb_scratch + width + 1;
|
||||||
const uint32_t* current_row = argb_scratch;
|
|
||||||
|
|
||||||
int y;
|
int y;
|
||||||
for (y = 0; y < max_y; ++y) {
|
VP8LPredictorFunc pred_func = 0;
|
||||||
|
|
||||||
|
for (y = 0; y < height; ++y) {
|
||||||
int x;
|
int x;
|
||||||
const int row = row_start + y;
|
uint32_t* tmp = upper_row;
|
||||||
const uint32_t* const upper_row = current_row;
|
upper_row = current_row;
|
||||||
current_row = upper_row + width;
|
current_row = tmp;
|
||||||
for (x = 0; x < max_x; ++x) {
|
memcpy(current_row, argb + y * width, sizeof(*current_row) * width);
|
||||||
const int col = col_start + x;
|
current_row[width] = (y + 1 < height) ? argb[(y + 1) * width] : ARGB_BLACK;
|
||||||
const int pix = row * width + col;
|
for (x = 0; x < width; ++x) {
|
||||||
uint32_t predict;
|
uint32_t predict;
|
||||||
if (row == 0) {
|
if ((x & mask) == 0) {
|
||||||
predict = (col == 0) ? ARGB_BLACK : current_row[col - 1]; // Left.
|
const int mode =
|
||||||
} else if (col == 0) {
|
(modes[(y >> bits) * tiles_per_row + (x >> bits)] >> 8) & 0xff;
|
||||||
predict = upper_row[col]; // Top.
|
pred_func = VP8LPredictors[mode];
|
||||||
} else {
|
|
||||||
predict = pred_func(current_row[col - 1], upper_row + col);
|
|
||||||
}
|
}
|
||||||
argb[pix] = VP8LSubPixels(current_row[col], predict);
|
if (y == 0) {
|
||||||
|
predict = (x == 0) ? ARGB_BLACK : current_row[x - 1]; // Left.
|
||||||
|
} else if (x == 0) {
|
||||||
|
predict = upper_row[x]; // Top.
|
||||||
|
} else {
|
||||||
|
predict = pred_func(current_row[x - 1], upper_row + x);
|
||||||
|
}
|
||||||
|
argb[y * width + x] = VP8LSubPixels(current_row[x], predict);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -705,35 +726,17 @@ void VP8LResidualImage(int width, int height, int bits, int low_effort,
|
|||||||
memcpy(current_tile_rows, &argb[tile_y_offset * width],
|
memcpy(current_tile_rows, &argb[tile_y_offset * width],
|
||||||
this_tile_height * width * sizeof(*current_tile_rows));
|
this_tile_height * width * sizeof(*current_tile_rows));
|
||||||
for (tile_x = 0; tile_x < tiles_per_row; ++tile_x) {
|
for (tile_x = 0; tile_x < tiles_per_row; ++tile_x) {
|
||||||
int pred;
|
const int pred =
|
||||||
int y;
|
low_effort ? kPredLowEffort :
|
||||||
const int tile_x_offset = tile_x * max_tile_size;
|
GetBestPredictorForTile(width, height,
|
||||||
int all_x_max = tile_x_offset + max_tile_size;
|
tile_x, tile_y, bits,
|
||||||
if (all_x_max > width) {
|
(int (*)[256])histo,
|
||||||
all_x_max = width;
|
argb_scratch);
|
||||||
}
|
|
||||||
pred = low_effort ? kPredLowEffort :
|
|
||||||
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);
|
image[tile_y * tiles_per_row + tile_x] = 0xff000000u | (pred << 8);
|
||||||
CopyTileWithPrediction(width, height, tile_x, tile_y, bits, pred,
|
|
||||||
argb_scratch, argb);
|
|
||||||
if (!low_effort) {
|
|
||||||
for (y = 0; y < max_tile_size; ++y) {
|
|
||||||
int all_x;
|
|
||||||
int all_y = tile_y_offset + y;
|
|
||||||
if (all_y >= height) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
for (all_x = tile_x_offset; all_x < all_x_max; ++all_x) {
|
|
||||||
UpdateHisto(histo, argb[all_y * width + all_x]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CopyImageWithPrediction(width, height, bits, image, argb_scratch, argb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VP8LSubtractGreenFromBlueAndRed_C(uint32_t* argb_data, int num_pixels) {
|
void VP8LSubtractGreenFromBlueAndRed_C(uint32_t* argb_data, int num_pixels) {
|
||||||
|
@ -1123,8 +1123,10 @@ static WebPEncodingError AllocateTransformBuffer(VP8LEncoder* const enc,
|
|||||||
if (enc->argb_ == NULL) {
|
if (enc->argb_ == NULL) {
|
||||||
const int tile_size = 1 << enc->transform_bits_;
|
const int tile_size = 1 << enc->transform_bits_;
|
||||||
const uint64_t image_size = width * height;
|
const uint64_t image_size = width * height;
|
||||||
|
// Ensure enough size for tiles, as well as for two scanlines and two
|
||||||
|
// extra pixels for CopyImageWithPrediction.
|
||||||
const uint64_t argb_scratch_size =
|
const uint64_t argb_scratch_size =
|
||||||
enc->use_predict_ ? tile_size * width + width : 0;
|
enc->use_predict_ ? tile_size * width + width + 2 : 0;
|
||||||
const int transform_data_size =
|
const int transform_data_size =
|
||||||
(enc->use_predict_ || enc->use_cross_color_)
|
(enc->use_predict_ || enc->use_cross_color_)
|
||||||
? VP8LSubSampleSize(width, enc->transform_bits_) *
|
? VP8LSubSampleSize(width, enc->transform_bits_) *
|
||||||
|
Loading…
x
Reference in New Issue
Block a user