| OLD | NEW |
| 1 // Copyright 2011 Google Inc. All Rights Reserved. | 1 // Copyright 2011 Google Inc. All Rights Reserved. |
| 2 // | 2 // |
| 3 // This code is licensed under the same terms as WebM: | 3 // This code is licensed under the same terms as WebM: |
| 4 // Software License Agreement: http://www.webmproject.org/license/software/ | 4 // Software License Agreement: http://www.webmproject.org/license/software/ |
| 5 // Additional IP Rights Grant: http://www.webmproject.org/license/additional/ | 5 // Additional IP Rights Grant: http://www.webmproject.org/license/additional/ |
| 6 // ----------------------------------------------------------------------------- | 6 // ----------------------------------------------------------------------------- |
| 7 // | 7 // |
| 8 // Spatial prediction using various filters | 8 // Spatial prediction using various filters |
| 9 // | 9 // |
| 10 // Author: Urvang (urvang@google.com) | 10 // Author: Urvang (urvang@google.com) |
| 11 | 11 |
| 12 #include "./filters.h" | 12 #include "./filters.h" |
| 13 #include <assert.h> | 13 #include <assert.h> |
| 14 #include <stdlib.h> | 14 #include <stdlib.h> |
| 15 #include <string.h> | 15 #include <string.h> |
| 16 | 16 |
| 17 #if defined(__cplusplus) || defined(c_plusplus) | 17 #if defined(__cplusplus) || defined(c_plusplus) |
| 18 extern "C" { | 18 extern "C" { |
| 19 #endif | 19 #endif |
| 20 | 20 |
| 21 //------------------------------------------------------------------------------ | 21 //------------------------------------------------------------------------------ |
| 22 // Helpful macro. | 22 // Helpful macro. |
| 23 | 23 |
| 24 # define SANITY_CHECK(in, out) \ | 24 # define SANITY_CHECK(in, out) \ |
| 25 assert(in != NULL); \ | 25 assert(in != NULL); \ |
| 26 assert(out != NULL); \ | 26 assert(out != NULL); \ |
| 27 assert(width > 0); \ | 27 assert(width > 0); \ |
| 28 assert(height > 0); \ | 28 assert(height > 0); \ |
| 29 assert(bpp > 0); \ | 29 assert(stride >= width); |
| 30 assert(stride >= width * bpp); | |
| 31 | 30 |
| 32 static WEBP_INLINE void PredictLine(const uint8_t* src, const uint8_t* pred, | 31 static WEBP_INLINE void PredictLine(const uint8_t* src, const uint8_t* pred, |
| 33 uint8_t* dst, int length, int inverse) { | 32 uint8_t* dst, int length, int inverse) { |
| 34 int i; | 33 int i; |
| 35 if (inverse) { | 34 if (inverse) { |
| 36 for (i = 0; i < length; ++i) dst[i] = src[i] + pred[i]; | 35 for (i = 0; i < length; ++i) dst[i] = src[i] + pred[i]; |
| 37 } else { | 36 } else { |
| 38 for (i = 0; i < length; ++i) dst[i] = src[i] - pred[i]; | 37 for (i = 0; i < length; ++i) dst[i] = src[i] - pred[i]; |
| 39 } | 38 } |
| 40 } | 39 } |
| 41 | 40 |
| 42 //------------------------------------------------------------------------------ | 41 //------------------------------------------------------------------------------ |
| 43 // Horizontal filter. | 42 // Horizontal filter. |
| 44 | 43 |
| 45 static WEBP_INLINE void DoHorizontalFilter(const uint8_t* in, | 44 static WEBP_INLINE void DoHorizontalFilter(const uint8_t* in, |
| 46 int width, int height, int bpp, int stride, int inverse, uint8_t* out) { | 45 int width, int height, int stride, |
| 46 int inverse, uint8_t* out) { |
| 47 int h; | 47 int h; |
| 48 const uint8_t* preds = (inverse ? out : in); | 48 const uint8_t* preds = (inverse ? out : in); |
| 49 SANITY_CHECK(in, out); | 49 SANITY_CHECK(in, out); |
| 50 | 50 |
| 51 // Filter line-by-line. | 51 // Filter line-by-line. |
| 52 for (h = 0; h < height; ++h) { | 52 for (h = 0; h < height; ++h) { |
| 53 // Leftmost pixel is predicted from above (except for topmost scanline). | 53 // Leftmost pixel is predicted from above (except for topmost scanline). |
| 54 if (h == 0) { | 54 if (h == 0) { |
| 55 memcpy((void*)out, (const void*)in, bpp); | 55 out[0] = in[0]; |
| 56 } else { | 56 } else { |
| 57 PredictLine(in, preds - stride, out, bpp, inverse); | 57 PredictLine(in, preds - stride, out, 1, inverse); |
| 58 } | 58 } |
| 59 PredictLine(in + bpp, preds, out + bpp, bpp * (width - 1), inverse); | 59 PredictLine(in + 1, preds, out + 1, width - 1, inverse); |
| 60 preds += stride; | 60 preds += stride; |
| 61 in += stride; | 61 in += stride; |
| 62 out += stride; | 62 out += stride; |
| 63 } | 63 } |
| 64 } | 64 } |
| 65 | 65 |
| 66 static void HorizontalFilter(const uint8_t* data, int width, int height, | 66 static void HorizontalFilter(const uint8_t* data, int width, int height, |
| 67 int bpp, int stride, uint8_t* filtered_data) { | 67 int stride, uint8_t* filtered_data) { |
| 68 DoHorizontalFilter(data, width, height, bpp, stride, 0, filtered_data); | 68 DoHorizontalFilter(data, width, height, stride, 0, filtered_data); |
| 69 } | 69 } |
| 70 | 70 |
| 71 static void HorizontalUnfilter(const uint8_t* data, int width, int height, | 71 static void HorizontalUnfilter(int width, int height, int stride, |
| 72 int bpp, int stride, uint8_t* recon_data) { | 72 uint8_t* data) { |
| 73 DoHorizontalFilter(data, width, height, bpp, stride, 1, recon_data); | 73 DoHorizontalFilter(data, width, height, stride, 1, data); |
| 74 } | 74 } |
| 75 | 75 |
| 76 //------------------------------------------------------------------------------ | 76 //------------------------------------------------------------------------------ |
| 77 // Vertical filter. | 77 // Vertical filter. |
| 78 | 78 |
| 79 static WEBP_INLINE void DoVerticalFilter(const uint8_t* in, | 79 static WEBP_INLINE void DoVerticalFilter(const uint8_t* in, |
| 80 int width, int height, int bpp, int stride, int inverse, uint8_t* out) { | 80 int width, int height, int stride, |
| 81 int inverse, uint8_t* out) { |
| 81 int h; | 82 int h; |
| 82 const uint8_t* preds = (inverse ? out : in); | 83 const uint8_t* preds = (inverse ? out : in); |
| 83 SANITY_CHECK(in, out); | 84 SANITY_CHECK(in, out); |
| 84 | 85 |
| 85 // Very first top-left pixel is copied. | 86 // Very first top-left pixel is copied. |
| 86 memcpy((void*)out, (const void*)in, bpp); | 87 out[0] = in[0]; |
| 87 // Rest of top scan-line is left-predicted. | 88 // Rest of top scan-line is left-predicted. |
| 88 PredictLine(in + bpp, preds, out + bpp, bpp * (width - 1), inverse); | 89 PredictLine(in + 1, preds, out + 1, width - 1, inverse); |
| 89 | 90 |
| 90 // Filter line-by-line. | 91 // Filter line-by-line. |
| 91 for (h = 1; h < height; ++h) { | 92 for (h = 1; h < height; ++h) { |
| 92 in += stride; | 93 in += stride; |
| 93 out += stride; | 94 out += stride; |
| 94 PredictLine(in, preds, out, bpp * width, inverse); | 95 PredictLine(in, preds, out, width, inverse); |
| 95 preds += stride; | 96 preds += stride; |
| 96 } | 97 } |
| 97 } | 98 } |
| 98 | 99 |
| 99 static void VerticalFilter(const uint8_t* data, int width, int height, | 100 static void VerticalFilter(const uint8_t* data, int width, int height, |
| 100 int bpp, int stride, uint8_t* filtered_data) { | 101 int stride, uint8_t* filtered_data) { |
| 101 DoVerticalFilter(data, width, height, bpp, stride, 0, filtered_data); | 102 DoVerticalFilter(data, width, height, stride, 0, filtered_data); |
| 102 } | 103 } |
| 103 | 104 |
| 104 static void VerticalUnfilter(const uint8_t* data, int width, int height, | 105 static void VerticalUnfilter(int width, int height, int stride, uint8_t* data) { |
| 105 int bpp, int stride, uint8_t* recon_data) { | 106 DoVerticalFilter(data, width, height, stride, 1, data); |
| 106 DoVerticalFilter(data, width, height, bpp, stride, 1, recon_data); | |
| 107 } | 107 } |
| 108 | 108 |
| 109 //------------------------------------------------------------------------------ | 109 //------------------------------------------------------------------------------ |
| 110 // Gradient filter. | 110 // Gradient filter. |
| 111 | 111 |
| 112 static WEBP_INLINE int GradientPredictor(uint8_t a, uint8_t b, uint8_t c) { | 112 static WEBP_INLINE int GradientPredictor(uint8_t a, uint8_t b, uint8_t c) { |
| 113 const int g = a + b - c; | 113 const int g = a + b - c; |
| 114 return (g < 0) ? 0 : (g > 255) ? 255 : g; | 114 return ((g & ~0xff) == 0) ? g : (g < 0) ? 0 : 255; // clip to 8bit |
| 115 } | 115 } |
| 116 | 116 |
| 117 static WEBP_INLINE | 117 static WEBP_INLINE |
| 118 void DoGradientFilter(const uint8_t* in, int width, int height, | 118 void DoGradientFilter(const uint8_t* in, int width, int height, |
| 119 int bpp, int stride, int inverse, uint8_t* out) { | 119 int stride, int inverse, uint8_t* out) { |
| 120 const uint8_t* preds = (inverse ? out : in); | 120 const uint8_t* preds = (inverse ? out : in); |
| 121 int h; | 121 int h; |
| 122 SANITY_CHECK(in, out); | 122 SANITY_CHECK(in, out); |
| 123 | 123 |
| 124 // left prediction for top scan-line | 124 // left prediction for top scan-line |
| 125 memcpy((void*)out, (const void*)in, bpp); | 125 out[0] = in[0]; |
| 126 PredictLine(in + bpp, preds, out + bpp, bpp * (width - 1), inverse); | 126 PredictLine(in + 1, preds, out + 1, width - 1, inverse); |
| 127 | 127 |
| 128 // Filter line-by-line. | 128 // Filter line-by-line. |
| 129 for (h = 1; h < height; ++h) { | 129 for (h = 1; h < height; ++h) { |
| 130 int w; | 130 int w; |
| 131 preds += stride; | 131 preds += stride; |
| 132 in += stride; | 132 in += stride; |
| 133 out += stride; | 133 out += stride; |
| 134 // leftmost pixel: predict from above. | 134 // leftmost pixel: predict from above. |
| 135 PredictLine(in, preds - stride, out, bpp, inverse); | 135 PredictLine(in, preds - stride, out, 1, inverse); |
| 136 for (w = bpp; w < width * bpp; ++w) { | 136 for (w = 1; w < width; ++w) { |
| 137 const int pred = GradientPredictor(preds[w - bpp], | 137 const int pred = GradientPredictor(preds[w - 1], |
| 138 preds[w - stride], | 138 preds[w - stride], |
| 139 preds[w - stride - bpp]); | 139 preds[w - stride - 1]); |
| 140 out[w] = in[w] + (inverse ? pred : -pred); | 140 out[w] = in[w] + (inverse ? pred : -pred); |
| 141 } | 141 } |
| 142 } | 142 } |
| 143 } | 143 } |
| 144 | 144 |
| 145 static void GradientFilter(const uint8_t* data, int width, int height, | 145 static void GradientFilter(const uint8_t* data, int width, int height, |
| 146 int bpp, int stride, uint8_t* filtered_data) { | 146 int stride, uint8_t* filtered_data) { |
| 147 DoGradientFilter(data, width, height, bpp, stride, 0, filtered_data); | 147 DoGradientFilter(data, width, height, stride, 0, filtered_data); |
| 148 } | 148 } |
| 149 | 149 |
| 150 static void GradientUnfilter(const uint8_t* data, int width, int height, | 150 static void GradientUnfilter(int width, int height, int stride, uint8_t* data) { |
| 151 int bpp, int stride, uint8_t* recon_data) { | 151 DoGradientFilter(data, width, height, stride, 1, data); |
| 152 DoGradientFilter(data, width, height, bpp, stride, 1, recon_data); | |
| 153 } | 152 } |
| 154 | 153 |
| 155 #undef SANITY_CHECK | 154 #undef SANITY_CHECK |
| 156 | 155 |
| 157 // ----------------------------------------------------------------------------- | 156 // ----------------------------------------------------------------------------- |
| 158 // Quick estimate of a potentially interesting filter mode to try, in addition | 157 // Quick estimate of a potentially interesting filter mode to try, in addition |
| 159 // to the default NONE. | 158 // to the default NONE. |
| 160 | 159 |
| 161 #define SMAX 16 | 160 #define SMAX 16 |
| 162 #define SDIFF(a, b) (abs((a) - (b)) >> 4) // Scoring diff, in [0..SMAX) | 161 #define SDIFF(a, b) (abs((a) - (b)) >> 4) // Scoring diff, in [0..SMAX) |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 208 | 207 |
| 209 //------------------------------------------------------------------------------ | 208 //------------------------------------------------------------------------------ |
| 210 | 209 |
| 211 const WebPFilterFunc WebPFilters[WEBP_FILTER_LAST] = { | 210 const WebPFilterFunc WebPFilters[WEBP_FILTER_LAST] = { |
| 212 NULL, // WEBP_FILTER_NONE | 211 NULL, // WEBP_FILTER_NONE |
| 213 HorizontalFilter, // WEBP_FILTER_HORIZONTAL | 212 HorizontalFilter, // WEBP_FILTER_HORIZONTAL |
| 214 VerticalFilter, // WEBP_FILTER_VERTICAL | 213 VerticalFilter, // WEBP_FILTER_VERTICAL |
| 215 GradientFilter // WEBP_FILTER_GRADIENT | 214 GradientFilter // WEBP_FILTER_GRADIENT |
| 216 }; | 215 }; |
| 217 | 216 |
| 218 const WebPFilterFunc WebPUnfilters[WEBP_FILTER_LAST] = { | 217 const WebPUnfilterFunc WebPUnfilters[WEBP_FILTER_LAST] = { |
| 219 NULL, // WEBP_FILTER_NONE | 218 NULL, // WEBP_FILTER_NONE |
| 220 HorizontalUnfilter, // WEBP_FILTER_HORIZONTAL | 219 HorizontalUnfilter, // WEBP_FILTER_HORIZONTAL |
| 221 VerticalUnfilter, // WEBP_FILTER_VERTICAL | 220 VerticalUnfilter, // WEBP_FILTER_VERTICAL |
| 222 GradientUnfilter // WEBP_FILTER_GRADIENT | 221 GradientUnfilter // WEBP_FILTER_GRADIENT |
| 223 }; | 222 }; |
| 224 | 223 |
| 225 //------------------------------------------------------------------------------ | 224 //------------------------------------------------------------------------------ |
| 226 | 225 |
| 227 #if defined(__cplusplus) || defined(c_plusplus) | 226 #if defined(__cplusplus) || defined(c_plusplus) |
| 228 } // extern "C" | 227 } // extern "C" |
| 229 #endif | 228 #endif |
| OLD | NEW |