Lossless decoder fix for a special transform order

Fix the lossless decoder for the case when it has to apply other
inverse transforms before applying Color indexing inverse transform.

The main idea is to make ColorIndexingInverse virtually in-place: we
use the fact that the argb_cache is allocated to accommodate all
*unpacked* pixels of a macro-row, not just *packed* pixels.

Change-Id: I27f11f3043f863dfd753cc2580bc5b36376800c4
This commit is contained in:
Urvang Joshi 2012-08-09 02:44:38 +05:30 committed by Gerrit Code Review
parent 62dd9bb242
commit a0a488554d
2 changed files with 23 additions and 7 deletions

View File

@ -615,20 +615,22 @@ static WEBP_INLINE HTreeGroup* GetHtreeGroupForPos(VP8LMetadata* const hdr,
typedef void (*ProcessRowsFunc)(VP8LDecoder* const dec, int row); typedef void (*ProcessRowsFunc)(VP8LDecoder* const dec, int row);
static void ApplyTransforms(VP8LDecoder* const dec, int num_rows, static void ApplyInverseTransforms(VP8LDecoder* const dec, int num_rows,
const uint32_t* const rows) { const uint32_t* const rows) {
int n = dec->next_transform_; int n = dec->next_transform_;
const int cache_pixs = dec->width_ * num_rows; const int cache_pixs = dec->width_ * num_rows;
uint32_t* rows_data = dec->argb_cache_;
const int start_row = dec->last_row_; const int start_row = dec->last_row_;
const int end_row = start_row + num_rows; const int end_row = start_row + num_rows;
const uint32_t* rows_in = rows;
uint32_t* const rows_out = dec->argb_cache_;
// Inverse transforms. // Inverse transforms.
// TODO: most transforms only need to operate on the cropped region only. // TODO: most transforms only need to operate on the cropped region only.
memcpy(rows_data, rows, cache_pixs * sizeof(*rows_data)); memcpy(rows_out, rows_in, cache_pixs * sizeof(*rows_out));
while (n-- > 0) { while (n-- > 0) {
VP8LTransform* const transform = &dec->transforms_[n]; VP8LTransform* const transform = &dec->transforms_[n];
VP8LInverseTransform(transform, start_row, end_row, rows, rows_data); VP8LInverseTransform(transform, start_row, end_row, rows_in, rows_out);
rows_in = rows_out;
} }
} }
@ -639,7 +641,7 @@ static void ProcessRows(VP8LDecoder* const dec, int row) {
const int num_rows = row - dec->last_row_; const int num_rows = row - dec->last_row_;
if (num_rows <= 0) return; // Nothing to be done. if (num_rows <= 0) return; // Nothing to be done.
ApplyTransforms(dec, num_rows, rows); ApplyInverseTransforms(dec, num_rows, rows);
// Emit output. // Emit output.
{ {
@ -1066,7 +1068,7 @@ static void ExtractAlphaRows(VP8LDecoder* const dec, int row) {
const uint32_t* const in = dec->argb_ + dec->width_ * dec->last_row_; const uint32_t* const in = dec->argb_ + dec->width_ * dec->last_row_;
if (num_rows <= 0) return; // Nothing to be done. if (num_rows <= 0) return; // Nothing to be done.
ApplyTransforms(dec, num_rows, in); ApplyInverseTransforms(dec, num_rows, in);
// Extract alpha (which is stored in the green plane). // Extract alpha (which is stored in the green plane).
{ {

View File

@ -935,7 +935,7 @@ static void ColorIndexInverseTransform(
uint32_t packed_pixels = 0; uint32_t packed_pixels = 0;
int x; int x;
for (x = 0; x < width; ++x) { for (x = 0; x < width; ++x) {
// We need to load fresh 'packed_pixels' once every 'bytes_per_pixels' // We need to load fresh 'packed_pixels' once every 'pixels_per_byte'
// increments of x. Fortunately, pixels_per_byte is a power of 2, so // increments of x. Fortunately, pixels_per_byte is a power of 2, so
// can just use a mask for that, instead of decrementing a counter. // can just use a mask for that, instead of decrementing a counter.
if ((x & count_mask) == 0) packed_pixels = ((*src++) >> 8) & 0xff; if ((x & count_mask) == 0) packed_pixels = ((*src++) >> 8) & 0xff;
@ -976,7 +976,21 @@ void VP8LInverseTransform(const VP8LTransform* const transform,
ColorSpaceInverseTransform(transform, row_start, row_end, out); ColorSpaceInverseTransform(transform, row_start, row_end, out);
break; break;
case COLOR_INDEXING_TRANSFORM: case COLOR_INDEXING_TRANSFORM:
if (in == out && transform->bits_ > 0) {
// Move packed pixels to the end of unpacked region, so that unpacking
// can occur seamlessly.
// Also, note that this is the only transform that applies on
// the effective width of VP8LSubSampleSize(xsize_, bits_). All other
// transforms work on effective width of xsize_.
const int out_stride = (row_end - row_start) * transform->xsize_;
const int in_stride = (row_end - row_start) *
VP8LSubSampleSize(transform->xsize_, transform->bits_);
uint32_t* const src = out + out_stride - in_stride;
memmove(src, out, in_stride * sizeof(*src));
ColorIndexInverseTransform(transform, row_start, row_end, src, out);
} else {
ColorIndexInverseTransform(transform, row_start, row_end, in, out); ColorIndexInverseTransform(transform, row_start, row_end, in, out);
}
break; break;
} }
} }