From 47374b8273917e90dc1737a308bbfeaafba5fd36 Mon Sep 17 00:00:00 2001 From: Urvang Joshi Date: Tue, 11 Jun 2013 15:57:42 -0700 Subject: [PATCH] Alpha unfilter for given set of rows Support reconstruction of small number of rows at a time. Change-Id: Ief1bc78c7ad011ec6df856551f3beb5f907fd8e0 --- src/dec/alpha.c | 2 +- src/utils/filters.c | 129 ++++++++++++++++++++++++++++---------------- src/utils/filters.h | 4 +- 3 files changed, 88 insertions(+), 47 deletions(-) diff --git a/src/dec/alpha.c b/src/dec/alpha.c index a905738e..752ea665 100644 --- a/src/dec/alpha.c +++ b/src/dec/alpha.c @@ -75,7 +75,7 @@ static int DecodeAlpha(const uint8_t* data, size_t data_size, if (unfilter_func != NULL) { // TODO(vikas): Implement on-the-fly decoding & filter mechanism to decode // and apply filter per image-row. - unfilter_func(width, height, width, output); + unfilter_func(width, height, width, 0, height, output); } if (pre_processing == ALPHA_PREPROCESSED_LEVELS) { ok = DequantizeLevels(output, width, height); diff --git a/src/utils/filters.c b/src/utils/filters.c index eb5bb34f..40254145 100644 --- a/src/utils/filters.c +++ b/src/utils/filters.c @@ -23,12 +23,14 @@ extern "C" { //------------------------------------------------------------------------------ // Helpful macro. -# define SANITY_CHECK(in, out) \ - assert(in != NULL); \ - assert(out != NULL); \ - assert(width > 0); \ - assert(height > 0); \ - assert(stride >= width); +# define SANITY_CHECK(in, out) \ + assert(in != NULL); \ + assert(out != NULL); \ + assert(width > 0); \ + assert(height > 0); \ + assert(stride >= width); \ + assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \ + (void)height; // Silence unused warning. static WEBP_INLINE void PredictLine(const uint8_t* src, const uint8_t* pred, uint8_t* dst, int length, int inverse) { @@ -45,20 +47,32 @@ static WEBP_INLINE void PredictLine(const uint8_t* src, const uint8_t* pred, static WEBP_INLINE void DoHorizontalFilter(const uint8_t* in, int width, int height, int stride, + int row, int num_rows, int inverse, uint8_t* out) { - int h; - const uint8_t* preds = (inverse ? out : in); + const uint8_t* preds; + const size_t start_offset = row * stride; + const int last_row = row + num_rows; SANITY_CHECK(in, out); + in += start_offset; + out += start_offset; + preds = inverse ? out : in; + + if (row == 0) { + // Leftmost pixel is the same as input for topmost scanline. + out[0] = in[0]; + PredictLine(in + 1, preds, out + 1, width - 1, inverse); + row = 1; + preds += stride; + in += stride; + out += stride; + } // Filter line-by-line. - for (h = 0; h < height; ++h) { - // Leftmost pixel is predicted from above (except for topmost scanline). - if (h == 0) { - out[0] = in[0]; - } else { - PredictLine(in, preds - stride, out, 1, inverse); - } + while (row < last_row) { + // Leftmost pixel is predicted from above. + PredictLine(in, preds - stride, out, 1, inverse); PredictLine(in + 1, preds, out + 1, width - 1, inverse); + ++row; preds += stride; in += stride; out += stride; @@ -67,12 +81,12 @@ static WEBP_INLINE void DoHorizontalFilter(const uint8_t* in, static void HorizontalFilter(const uint8_t* data, int width, int height, int stride, uint8_t* filtered_data) { - DoHorizontalFilter(data, width, height, stride, 0, filtered_data); + DoHorizontalFilter(data, width, height, stride, 0, height, 0, filtered_data); } -static void HorizontalUnfilter(int width, int height, int stride, - uint8_t* data) { - DoHorizontalFilter(data, width, height, stride, 1, data); +static void HorizontalUnfilter(int width, int height, int stride, int row, + int num_rows, uint8_t* data) { + DoHorizontalFilter(data, width, height, stride, row, num_rows, 1, data); } //------------------------------------------------------------------------------ @@ -80,32 +94,44 @@ static void HorizontalUnfilter(int width, int height, int stride, static WEBP_INLINE void DoVerticalFilter(const uint8_t* in, int width, int height, int stride, + int row, int num_rows, int inverse, uint8_t* out) { - int h; - const uint8_t* preds = (inverse ? out : in); + const uint8_t* preds; + const size_t start_offset = row * stride; + const int last_row = row + num_rows; SANITY_CHECK(in, out); + in += start_offset; + out += start_offset; + preds = inverse ? out : in; - // Very first top-left pixel is copied. - out[0] = in[0]; - // Rest of top scan-line is left-predicted. - PredictLine(in + 1, preds, out + 1, width - 1, inverse); - - // Filter line-by-line. - for (h = 1; h < height; ++h) { + if (row == 0) { + // Very first top-left pixel is copied. + out[0] = in[0]; + // Rest of top scan-line is left-predicted. + PredictLine(in + 1, preds, out + 1, width - 1, inverse); + row = 1; in += stride; out += stride; + } + + // Filter line-by-line. + while (row < last_row) { PredictLine(in, preds, out, width, inverse); + ++row; preds += stride; + in += stride; + out += stride; } } static void VerticalFilter(const uint8_t* data, int width, int height, int stride, uint8_t* filtered_data) { - DoVerticalFilter(data, width, height, stride, 0, filtered_data); + DoVerticalFilter(data, width, height, stride, 0, height, 0, filtered_data); } -static void VerticalUnfilter(int width, int height, int stride, uint8_t* data) { - DoVerticalFilter(data, width, height, stride, 1, data); +static void VerticalUnfilter(int width, int height, int stride, int row, + int num_rows, uint8_t* data) { + DoVerticalFilter(data, width, height, stride, row, num_rows, 1, data); } //------------------------------------------------------------------------------ @@ -116,23 +142,31 @@ static WEBP_INLINE int GradientPredictor(uint8_t a, uint8_t b, uint8_t c) { return ((g & ~0xff) == 0) ? g : (g < 0) ? 0 : 255; // clip to 8bit } -static WEBP_INLINE -void DoGradientFilter(const uint8_t* in, int width, int height, - int stride, int inverse, uint8_t* out) { - const uint8_t* preds = (inverse ? out : in); - int h; +static WEBP_INLINE void DoGradientFilter(const uint8_t* in, + int width, int height, int stride, + int row, int num_rows, + int inverse, uint8_t* out) { + const uint8_t* preds; + const size_t start_offset = row * stride; + const int last_row = row + num_rows; SANITY_CHECK(in, out); + in += start_offset; + out += start_offset; + preds = inverse ? out : in; // left prediction for top scan-line - out[0] = in[0]; - PredictLine(in + 1, preds, out + 1, width - 1, inverse); - - // Filter line-by-line. - for (h = 1; h < height; ++h) { - int w; + if (row == 0) { + out[0] = in[0]; + PredictLine(in + 1, preds, out + 1, width - 1, inverse); + row = 1; preds += stride; in += stride; out += stride; + } + + // Filter line-by-line. + while (row < last_row) { + int w; // leftmost pixel: predict from above. PredictLine(in, preds - stride, out, 1, inverse); for (w = 1; w < width; ++w) { @@ -141,16 +175,21 @@ void DoGradientFilter(const uint8_t* in, int width, int height, preds[w - stride - 1]); out[w] = in[w] + (inverse ? pred : -pred); } + ++row; + preds += stride; + in += stride; + out += stride; } } static void GradientFilter(const uint8_t* data, int width, int height, int stride, uint8_t* filtered_data) { - DoGradientFilter(data, width, height, stride, 0, filtered_data); + DoGradientFilter(data, width, height, stride, 0, height, 0, filtered_data); } -static void GradientUnfilter(int width, int height, int stride, uint8_t* data) { - DoGradientFilter(data, width, height, stride, 1, data); +static void GradientUnfilter(int width, int height, int stride, int row, + int num_rows, uint8_t* data) { + DoGradientFilter(data, width, height, stride, row, num_rows, 1, data); } #undef SANITY_CHECK diff --git a/src/utils/filters.h b/src/utils/filters.h index 1f5fa164..ace8d309 100644 --- a/src/utils/filters.h +++ b/src/utils/filters.h @@ -34,7 +34,7 @@ typedef enum { typedef void (*WebPFilterFunc)(const uint8_t* in, int width, int height, int stride, uint8_t* out); typedef void (*WebPUnfilterFunc)(int width, int height, int stride, - uint8_t* data); + int row, int num_rows, uint8_t* data); // Filter the given data using the given predictor. // 'in' corresponds to a 2-dimensional pixel array of size (stride * height) @@ -44,6 +44,8 @@ typedef void (*WebPUnfilterFunc)(int width, int height, int stride, extern const WebPFilterFunc WebPFilters[WEBP_FILTER_LAST]; // In-place reconstruct the original data from the given filtered data. +// The reconstruction will be done for 'num_rows' rows starting from 'row' +// (assuming rows upto 'row - 1' are already reconstructed). extern const WebPUnfilterFunc WebPUnfilters[WEBP_FILTER_LAST]; // Fast estimate of a potentially good filter.