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