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