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