1 : /*
2 : * Copyright (c) 2010 The WebM project authors. All Rights Reserved.
3 : *
4 : * Use of this source code is governed by a BSD-style license
5 : * that can be found in the LICENSE file in the root of the source
6 : * tree. An additional intellectual property rights grant can be found
7 : * in the file PATENTS. All contributing project authors may
8 : * be found in the AUTHORS file in the root of the source tree.
9 : */
10 :
11 :
12 : #include <stdlib.h>
13 : #include "loopfilter.h"
14 : #include "onyxc_int.h"
15 :
16 : #ifdef __SUNPRO_C
17 : #define __inline inline
18 : #endif
19 :
20 : typedef unsigned char uc;
21 :
22 0 : static __inline signed char vp8_signed_char_clamp(int t)
23 : {
24 0 : t = (t < -128 ? -128 : t);
25 0 : t = (t > 127 ? 127 : t);
26 0 : return (signed char) t;
27 : }
28 :
29 :
30 : /* should we apply any filter at all ( 11111111 yes, 00000000 no) */
31 0 : static __inline signed char vp8_filter_mask(uc limit, uc blimit,
32 : uc p3, uc p2, uc p1, uc p0,
33 : uc q0, uc q1, uc q2, uc q3)
34 : {
35 0 : signed char mask = 0;
36 0 : mask |= (abs(p3 - p2) > limit) * -1;
37 0 : mask |= (abs(p2 - p1) > limit) * -1;
38 0 : mask |= (abs(p1 - p0) > limit) * -1;
39 0 : mask |= (abs(q1 - q0) > limit) * -1;
40 0 : mask |= (abs(q2 - q1) > limit) * -1;
41 0 : mask |= (abs(q3 - q2) > limit) * -1;
42 0 : mask |= (abs(p0 - q0) * 2 + abs(p1 - q1) / 2 > blimit) * -1;
43 0 : mask = ~mask;
44 0 : return mask;
45 : }
46 :
47 : /* is there high variance internal edge ( 11111111 yes, 00000000 no) */
48 0 : static __inline signed char vp8_hevmask(uc thresh, uc p1, uc p0, uc q0, uc q1)
49 : {
50 0 : signed char hev = 0;
51 0 : hev |= (abs(p1 - p0) > thresh) * -1;
52 0 : hev |= (abs(q1 - q0) > thresh) * -1;
53 0 : return hev;
54 : }
55 :
56 0 : static __inline void vp8_filter(signed char mask, uc hev, uc *op1,
57 : uc *op0, uc *oq0, uc *oq1)
58 :
59 : {
60 : signed char ps0, qs0;
61 : signed char ps1, qs1;
62 : signed char vp8_filter, Filter1, Filter2;
63 : signed char u;
64 :
65 0 : ps1 = (signed char) * op1 ^ 0x80;
66 0 : ps0 = (signed char) * op0 ^ 0x80;
67 0 : qs0 = (signed char) * oq0 ^ 0x80;
68 0 : qs1 = (signed char) * oq1 ^ 0x80;
69 :
70 : /* add outer taps if we have high edge variance */
71 0 : vp8_filter = vp8_signed_char_clamp(ps1 - qs1);
72 0 : vp8_filter &= hev;
73 :
74 : /* inner taps */
75 0 : vp8_filter = vp8_signed_char_clamp(vp8_filter + 3 * (qs0 - ps0));
76 0 : vp8_filter &= mask;
77 :
78 : /* save bottom 3 bits so that we round one side +4 and the other +3
79 : * if it equals 4 we'll set to adjust by -1 to account for the fact
80 : * we'd round 3 the other way
81 : */
82 0 : Filter1 = vp8_signed_char_clamp(vp8_filter + 4);
83 0 : Filter2 = vp8_signed_char_clamp(vp8_filter + 3);
84 0 : Filter1 >>= 3;
85 0 : Filter2 >>= 3;
86 0 : u = vp8_signed_char_clamp(qs0 - Filter1);
87 0 : *oq0 = u ^ 0x80;
88 0 : u = vp8_signed_char_clamp(ps0 + Filter2);
89 0 : *op0 = u ^ 0x80;
90 0 : vp8_filter = Filter1;
91 :
92 : /* outer tap adjustments */
93 0 : vp8_filter += 1;
94 0 : vp8_filter >>= 1;
95 0 : vp8_filter &= ~hev;
96 :
97 0 : u = vp8_signed_char_clamp(qs1 - vp8_filter);
98 0 : *oq1 = u ^ 0x80;
99 0 : u = vp8_signed_char_clamp(ps1 + vp8_filter);
100 0 : *op1 = u ^ 0x80;
101 :
102 0 : }
103 0 : void vp8_loop_filter_horizontal_edge_c
104 : (
105 : unsigned char *s,
106 : int p, /* pitch */
107 : const unsigned char *blimit,
108 : const unsigned char *limit,
109 : const unsigned char *thresh,
110 : int count
111 : )
112 : {
113 0 : int hev = 0; /* high edge variance */
114 0 : signed char mask = 0;
115 0 : int i = 0;
116 :
117 : /* loop filter designed to work using chars so that we can make maximum use
118 : * of 8 bit simd instructions.
119 : */
120 : do
121 : {
122 0 : mask = vp8_filter_mask(limit[0], blimit[0],
123 0 : s[-4*p], s[-3*p], s[-2*p], s[-1*p],
124 0 : s[0*p], s[1*p], s[2*p], s[3*p]);
125 :
126 0 : hev = vp8_hevmask(thresh[0], s[-2*p], s[-1*p], s[0*p], s[1*p]);
127 :
128 0 : vp8_filter(mask, hev, s - 2 * p, s - 1 * p, s, s + 1 * p);
129 :
130 0 : ++s;
131 : }
132 0 : while (++i < count * 8);
133 0 : }
134 :
135 0 : void vp8_loop_filter_vertical_edge_c
136 : (
137 : unsigned char *s,
138 : int p,
139 : const unsigned char *blimit,
140 : const unsigned char *limit,
141 : const unsigned char *thresh,
142 : int count
143 : )
144 : {
145 0 : int hev = 0; /* high edge variance */
146 0 : signed char mask = 0;
147 0 : int i = 0;
148 :
149 : /* loop filter designed to work using chars so that we can make maximum use
150 : * of 8 bit simd instructions.
151 : */
152 : do
153 : {
154 0 : mask = vp8_filter_mask(limit[0], blimit[0],
155 0 : s[-4], s[-3], s[-2], s[-1], s[0], s[1], s[2], s[3]);
156 :
157 0 : hev = vp8_hevmask(thresh[0], s[-2], s[-1], s[0], s[1]);
158 :
159 0 : vp8_filter(mask, hev, s - 2, s - 1, s, s + 1);
160 :
161 0 : s += p;
162 : }
163 0 : while (++i < count * 8);
164 0 : }
165 :
166 0 : static __inline void vp8_mbfilter(signed char mask, uc hev,
167 : uc *op2, uc *op1, uc *op0, uc *oq0, uc *oq1, uc *oq2)
168 : {
169 : signed char s, u;
170 : signed char vp8_filter, Filter1, Filter2;
171 0 : signed char ps2 = (signed char) * op2 ^ 0x80;
172 0 : signed char ps1 = (signed char) * op1 ^ 0x80;
173 0 : signed char ps0 = (signed char) * op0 ^ 0x80;
174 0 : signed char qs0 = (signed char) * oq0 ^ 0x80;
175 0 : signed char qs1 = (signed char) * oq1 ^ 0x80;
176 0 : signed char qs2 = (signed char) * oq2 ^ 0x80;
177 :
178 : /* add outer taps if we have high edge variance */
179 0 : vp8_filter = vp8_signed_char_clamp(ps1 - qs1);
180 0 : vp8_filter = vp8_signed_char_clamp(vp8_filter + 3 * (qs0 - ps0));
181 0 : vp8_filter &= mask;
182 :
183 0 : Filter2 = vp8_filter;
184 0 : Filter2 &= hev;
185 :
186 : /* save bottom 3 bits so that we round one side +4 and the other +3 */
187 0 : Filter1 = vp8_signed_char_clamp(Filter2 + 4);
188 0 : Filter2 = vp8_signed_char_clamp(Filter2 + 3);
189 0 : Filter1 >>= 3;
190 0 : Filter2 >>= 3;
191 0 : qs0 = vp8_signed_char_clamp(qs0 - Filter1);
192 0 : ps0 = vp8_signed_char_clamp(ps0 + Filter2);
193 :
194 :
195 : /* only apply wider filter if not high edge variance */
196 0 : vp8_filter &= ~hev;
197 0 : Filter2 = vp8_filter;
198 :
199 : /* roughly 3/7th difference across boundary */
200 0 : u = vp8_signed_char_clamp((63 + Filter2 * 27) >> 7);
201 0 : s = vp8_signed_char_clamp(qs0 - u);
202 0 : *oq0 = s ^ 0x80;
203 0 : s = vp8_signed_char_clamp(ps0 + u);
204 0 : *op0 = s ^ 0x80;
205 :
206 : /* roughly 2/7th difference across boundary */
207 0 : u = vp8_signed_char_clamp((63 + Filter2 * 18) >> 7);
208 0 : s = vp8_signed_char_clamp(qs1 - u);
209 0 : *oq1 = s ^ 0x80;
210 0 : s = vp8_signed_char_clamp(ps1 + u);
211 0 : *op1 = s ^ 0x80;
212 :
213 : /* roughly 1/7th difference across boundary */
214 0 : u = vp8_signed_char_clamp((63 + Filter2 * 9) >> 7);
215 0 : s = vp8_signed_char_clamp(qs2 - u);
216 0 : *oq2 = s ^ 0x80;
217 0 : s = vp8_signed_char_clamp(ps2 + u);
218 0 : *op2 = s ^ 0x80;
219 0 : }
220 :
221 0 : void vp8_mbloop_filter_horizontal_edge_c
222 : (
223 : unsigned char *s,
224 : int p,
225 : const unsigned char *blimit,
226 : const unsigned char *limit,
227 : const unsigned char *thresh,
228 : int count
229 : )
230 : {
231 0 : signed char hev = 0; /* high edge variance */
232 0 : signed char mask = 0;
233 0 : int i = 0;
234 :
235 : /* loop filter designed to work using chars so that we can make maximum use
236 : * of 8 bit simd instructions.
237 : */
238 : do
239 : {
240 :
241 0 : mask = vp8_filter_mask(limit[0], blimit[0],
242 0 : s[-4*p], s[-3*p], s[-2*p], s[-1*p],
243 0 : s[0*p], s[1*p], s[2*p], s[3*p]);
244 :
245 0 : hev = vp8_hevmask(thresh[0], s[-2*p], s[-1*p], s[0*p], s[1*p]);
246 :
247 0 : vp8_mbfilter(mask, hev, s - 3 * p, s - 2 * p, s - 1 * p, s, s + 1 * p, s + 2 * p);
248 :
249 0 : ++s;
250 : }
251 0 : while (++i < count * 8);
252 :
253 0 : }
254 :
255 :
256 0 : void vp8_mbloop_filter_vertical_edge_c
257 : (
258 : unsigned char *s,
259 : int p,
260 : const unsigned char *blimit,
261 : const unsigned char *limit,
262 : const unsigned char *thresh,
263 : int count
264 : )
265 : {
266 0 : signed char hev = 0; /* high edge variance */
267 0 : signed char mask = 0;
268 0 : int i = 0;
269 :
270 : do
271 : {
272 :
273 0 : mask = vp8_filter_mask(limit[0], blimit[0],
274 0 : s[-4], s[-3], s[-2], s[-1], s[0], s[1], s[2], s[3]);
275 :
276 0 : hev = vp8_hevmask(thresh[0], s[-2], s[-1], s[0], s[1]);
277 :
278 0 : vp8_mbfilter(mask, hev, s - 3, s - 2, s - 1, s, s + 1, s + 2);
279 :
280 0 : s += p;
281 : }
282 0 : while (++i < count * 8);
283 :
284 0 : }
285 :
286 : /* should we apply any filter at all ( 11111111 yes, 00000000 no) */
287 0 : static __inline signed char vp8_simple_filter_mask(uc blimit, uc p1, uc p0, uc q0, uc q1)
288 : {
289 : /* Why does this cause problems for win32?
290 : * error C2143: syntax error : missing ';' before 'type'
291 : * (void) limit;
292 : */
293 0 : signed char mask = (abs(p0 - q0) * 2 + abs(p1 - q1) / 2 <= blimit) * -1;
294 0 : return mask;
295 : }
296 :
297 0 : static __inline void vp8_simple_filter(signed char mask, uc *op1, uc *op0, uc *oq0, uc *oq1)
298 : {
299 : signed char vp8_filter, Filter1, Filter2;
300 0 : signed char p1 = (signed char) * op1 ^ 0x80;
301 0 : signed char p0 = (signed char) * op0 ^ 0x80;
302 0 : signed char q0 = (signed char) * oq0 ^ 0x80;
303 0 : signed char q1 = (signed char) * oq1 ^ 0x80;
304 : signed char u;
305 :
306 0 : vp8_filter = vp8_signed_char_clamp(p1 - q1);
307 0 : vp8_filter = vp8_signed_char_clamp(vp8_filter + 3 * (q0 - p0));
308 0 : vp8_filter &= mask;
309 :
310 : /* save bottom 3 bits so that we round one side +4 and the other +3 */
311 0 : Filter1 = vp8_signed_char_clamp(vp8_filter + 4);
312 0 : Filter1 >>= 3;
313 0 : u = vp8_signed_char_clamp(q0 - Filter1);
314 0 : *oq0 = u ^ 0x80;
315 :
316 0 : Filter2 = vp8_signed_char_clamp(vp8_filter + 3);
317 0 : Filter2 >>= 3;
318 0 : u = vp8_signed_char_clamp(p0 + Filter2);
319 0 : *op0 = u ^ 0x80;
320 0 : }
321 :
322 0 : void vp8_loop_filter_simple_horizontal_edge_c
323 : (
324 : unsigned char *s,
325 : int p,
326 : const unsigned char *blimit
327 : )
328 : {
329 0 : signed char mask = 0;
330 0 : int i = 0;
331 :
332 : do
333 : {
334 0 : mask = vp8_simple_filter_mask(blimit[0], s[-2*p], s[-1*p], s[0*p], s[1*p]);
335 0 : vp8_simple_filter(mask, s - 2 * p, s - 1 * p, s, s + 1 * p);
336 0 : ++s;
337 : }
338 0 : while (++i < 16);
339 0 : }
340 :
341 0 : void vp8_loop_filter_simple_vertical_edge_c
342 : (
343 : unsigned char *s,
344 : int p,
345 : const unsigned char *blimit
346 : )
347 : {
348 0 : signed char mask = 0;
349 0 : int i = 0;
350 :
351 : do
352 : {
353 0 : mask = vp8_simple_filter_mask(blimit[0], s[-2], s[-1], s[0], s[1]);
354 0 : vp8_simple_filter(mask, s - 2, s - 1, s, s + 1);
355 0 : s += p;
356 : }
357 0 : while (++i < 16);
358 :
359 0 : }
|