From b2f99465a7d4eabe5ca21ab55d7604598ecd718b Mon Sep 17 00:00:00 2001 From: Urvang Joshi Date: Fri, 13 Apr 2012 07:01:11 +0000 Subject: [PATCH] Fix CopyTileWithPrediction() so that it uses original values of left, top etc for prediction rather than the predicted values of the same. Also, do some renaming in the same to make it more readable. Change-Id: I2fe94e35a6700bd437f5c601e2af12323bf32445 --- src/dsp/lossless.c | 56 ++++++++++++++++++++++++++++------------------ src/dsp/lossless.h | 9 +++++--- src/enc/vp8l.c | 30 ++++++++++++------------- src/enc/vp8li.h | 2 ++ 4 files changed, 57 insertions(+), 40 deletions(-) diff --git a/src/dsp/lossless.c b/src/dsp/lossless.c index f5da54ba..657a67bd 100644 --- a/src/dsp/lossless.c +++ b/src/dsp/lossless.c @@ -398,44 +398,55 @@ static int GetBestPredictorForTile(int tile_x, int tile_y, int max_tile_size, return best_mode; } -static void CopyTileWithPrediction(int xsize, int ysize, +static void CopyTileWithPrediction(int width, int height, int tile_x, int tile_y, int bits, int mode, + uint32_t* const argb_scratch, uint32_t* const argb) { - int ymax = 1 << bits; - int xmax = 1 << bits; - int y; + const int col_start = tile_x << bits; + const int row_start = tile_y << bits; + const int transform_size = 1 << bits; + const int ymax = (transform_size <= height - row_start) ? + transform_size : height - row_start; + const int xmax = (transform_size <= width - col_start) ? + transform_size : width - col_start; const PredictorFunc pred_func = kPredictors[mode]; - if (ymax > ysize - (tile_y << bits)) { - ymax = ysize - (tile_y << bits); - } - if (xmax > xsize - (tile_x << bits)) { - xmax = xsize - (tile_x << bits); - } + uint32_t* const top_row = argb_scratch; + uint32_t* const current_row = argb_scratch + width; + + int y; for (y = 0; y < ymax; ++y) { - const int all_y = (tile_y << bits) + y; int x; + const int row = row_start + y; + // Update current_row & top_row. + if (row > 0) { + memcpy(top_row, current_row, width * sizeof(*top_row)); + } + memcpy(current_row, &argb[row * width], width * sizeof(*current_row)); for (x = 0; x < xmax; ++x) { - const int all_x = (tile_x << bits) + x; - const int ix = all_y * xsize + all_x; + const int col = col_start + x; + const int pix = row * width + col; uint32_t predict; - if (all_y == 0) { - if (all_x == 0) { + if (row == 0) { + if (col == 0) { predict = ARGB_BLACK; } else { - predict = argb[ix - 1]; + const uint32_t left = current_row[col - 1]; + predict = left; } - } else if (all_x == 0) { - predict = argb[ix - xsize]; + } else if (col == 0) { + const uint32_t top = top_row[col]; + predict = top; } else { - predict = pred_func(argb + ix, argb + ix - xsize); + predict = pred_func(argb + pix, top_row + col); } - argb[ix] = VP8LSubPixels(argb[ix], predict); + argb[pix] = VP8LSubPixels(argb[pix], predict); } } } void VP8LResidualImage(int width, int height, int bits, - uint32_t* const argb, uint32_t* const image) { + uint32_t* const argb, uint32_t* const argb_scratch, + uint32_t* const image) { const int max_tile_size = 1 << bits; const int tile_xsize = VP8LSubSampleSize(width, bits); const int tile_ysize = VP8LSubSampleSize(height, bits); @@ -456,7 +467,8 @@ void VP8LResidualImage(int width, int height, int bits, pred = GetBestPredictorForTile(tile_x, tile_y, max_tile_size, width, height, histo, argb); image[tile_y * tile_xsize + tile_x] = 0xff000000u | (pred << 8); - CopyTileWithPrediction(width, height, tile_x, tile_y, bits, pred, argb); + CopyTileWithPrediction(width, height, tile_x, tile_y, bits, pred, + argb_scratch, argb); for (y = 0; y < max_tile_size; ++y) { int ix; int all_x; diff --git a/src/dsp/lossless.h b/src/dsp/lossless.h index 2ea4e31a..26c8ab02 100644 --- a/src/dsp/lossless.h +++ b/src/dsp/lossless.h @@ -38,7 +38,8 @@ void VP8LInverseTransform(const struct VP8LTransform* const transform, void VP8LSubtractGreenFromBlueAndRed(uint32_t* argb_data, int num_pixs); void VP8LResidualImage(int width, int height, int bits, - uint32_t* const argb, uint32_t* const image); + uint32_t* const argb, uint32_t* const argb_scratch, + uint32_t* const image); void VP8LColorSpaceTransform(int width, int height, int bits, int step, uint32_t* const argb, uint32_t* image); @@ -67,8 +68,10 @@ double VP8LFastLog(int v); // In-place difference of each component with mod 256. static WEBP_INLINE uint32_t VP8LSubPixels(uint32_t a, uint32_t b) { - const uint32_t alpha_and_green = (a & 0xff00ff00u) - (b & 0xff00ff00u); - const uint32_t red_and_blue = (a & 0x00ff00ffu) - (b & 0x00ff00ffu); + const uint32_t alpha_and_green = + 0x00ff00ffu + (a & 0xff00ff00u) - (b & 0xff00ff00u); + const uint32_t red_and_blue = + 0xff00ff00u + (a & 0x00ff00ffu) - (b & 0x00ff00ffu); return (alpha_and_green & 0xff00ff00u) | (red_and_blue & 0x00ff00ffu); } #endif diff --git a/src/enc/vp8l.c b/src/enc/vp8l.c index 2cf64401..2b002722 100644 --- a/src/enc/vp8l.c +++ b/src/enc/vp8l.c @@ -928,7 +928,8 @@ static int ApplyPredictFilter(VP8LBitWriter* const bw, const int transform_width = VP8LSubSampleSize(width, pred_bits); const int transform_height = VP8LSubSampleSize(height, pred_bits); - VP8LResidualImage(width, height, pred_bits, enc->argb_, enc->transform_data_); + VP8LResidualImage(width, height, pred_bits, enc->argb_, enc->argb_scratch_, + enc->transform_data_); VP8LWriteBits(bw, 1, 1); VP8LWriteBits(bw, 2, 0); VP8LWriteBits(bw, 4, pred_bits); @@ -1020,9 +1021,7 @@ static WebPEncodingError WriteImage(VP8LEncoder* const enc, static VP8LEncoder* InitVP8LEncoder(const WebPConfig* const config, WebPPicture* const picture) { - VP8LEncoder* enc; - - enc = (VP8LEncoder*)malloc(sizeof(*enc)); + VP8LEncoder* enc = (VP8LEncoder*)malloc(sizeof(*enc)); if (enc == NULL) { WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); return NULL; @@ -1034,8 +1033,6 @@ static VP8LEncoder* InitVP8LEncoder(const WebPConfig* const config, enc->use_lz77_ = 1; enc->palette_bits_ = 7; - enc->argb_ = NULL; - // TODO: Use config.quality to initialize histo_bits_ and transform_bits_. enc->histo_bits_ = 4; enc->transform_bits_ = 4; @@ -1058,25 +1055,28 @@ static void DeleteVP8LEncoder(VP8LEncoder* enc) { free(enc); } -// Allocates the memory for argb (W x H) buffer and transform data. -// Former buffer (argb_) will hold the argb data from successive image -// transformtions and later corresponds to prediction data (uint32) used -// for every image tile corresponding to the transformed argb_. -// The dimension of this square tile is 2^transform_bits_. +// Allocates the memory for argb (W x H) buffer, 2 rows of context for +// prediction and transform data. static WebPEncodingError AllocateTransformBuffer(VP8LEncoder* const enc, int height, int width) { WebPEncodingError err = VP8_ENC_OK; const size_t image_size = height * width; + const size_t argb_scratch_size = 2 * width; const size_t transform_data_size = VP8LSubSampleSize(height, enc->transform_bits_) * VP8LSubSampleSize(width, enc->transform_bits_); - const size_t total_size = image_size + transform_data_size; - enc->argb_ = (uint32_t*)malloc(total_size * sizeof(*enc->argb_)); - if (enc->argb_ == NULL) { + const size_t total_size = + image_size + argb_scratch_size + transform_data_size; + uint32_t* mem = (uint32_t*)malloc(total_size * sizeof(*mem)); + if (mem == NULL) { err = VP8_ENC_ERROR_OUT_OF_MEMORY; goto Error; } - enc->transform_data_ = enc->argb_ + image_size; + enc->argb_ = mem; + mem += image_size; + enc->argb_scratch_ = mem; + mem += argb_scratch_size; + enc->transform_data_ = mem; enc->current_width_ = width; Error: diff --git a/src/enc/vp8li.h b/src/enc/vp8li.h index 3a6ab927..a83b3993 100644 --- a/src/enc/vp8li.h +++ b/src/enc/vp8li.h @@ -38,6 +38,8 @@ typedef struct { WebPPicture* pic_; // input picture. uint32_t* argb_; // Transformed argb image data. + uint32_t* argb_scratch_; // Scratch memory for current and top row. + // (used for prediction). uint32_t* transform_data_; // Scratch memory for transform data. int current_width_; // Corresponds to packed image width.