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 |