r125: This commit was manufactured by cvs2svn to create tag 'r1_1_7-last'.
[cinelerra_cv/mob.git] / hvirtual / quicktime / decore50 / postprocess.c
blob790dd9c54bc76fd617d2d70adaff72be0220565b
1 /**************************************************************************
2 * *
3 * This code has been developed by John Funnell. This software is an *
4 * implementation of a part of one or more MPEG-4 Video tools as *
5 * specified in ISO/IEC 14496-2 standard. Those intending to use this *
6 * software module in hardware or software products are advised that its *
7 * use may infringe existing patents or copyrights, and any such use *
8 * would be at such party's own risk. The original developer of this *
9 * software module and his/her company, and subsequent editors and their *
10 * companies (including Project Mayo), will have no liability for use of *
11 * this software or modifications or derivatives thereof. *
12 * *
13 * Project Mayo gives users of the Codec a license to this software *
14 * module or modifications thereof for use in hardware or software *
15 * products claiming conformance to the MPEG-4 Video Standard as *
16 * described in the Open DivX license. *
17 * *
18 * The complete Open DivX license can be found at *
19 * http://www.projectmayo.com/opendivx/license.php *
20 * *
21 **************************************************************************/
22 /**
23 * Copyright (C) 2001 - Project Mayo
25 * John Funnell
27 * DivX Advanced Research Center <darc@projectmayo.com>
28 **/
29 // postprocess.c //
31 /* Currently this contains only the deblocking filter. The vertical */
32 /* deblocking filter operates over eight pixel-wide columns at once. The */
33 /* horizontal deblocking filter works on four horizontals row at a time. */
36 #include "postprocess.h"
38 #ifdef PP_SELF_CHECK
39 #include <stdio.h>
40 #endif
43 #define ABS(a) ( (a)>0 ? (a) : -(a) )
44 #define SIGN(a) ( (a)<0 ? -1 : 1 )
45 #define MIN(a, b) ( (a)<(b) ? (a) : (b) )
46 #define MAX(a, b) ( (a)>(b) ? (a) : (b) )
51 /***** H O R I Z O N T A L D E B L O C K I N G F I L T E R *****/
55 /* decide DC mode or default mode for the horizontal filter */
56 static int deblock_horiz_useDC(uint8_t *v, int stride) {
57 int eq_cnt, useDC;
58 int x, y;
59 #ifdef PP_SELF_CHECK
60 int eq_cnt2, j, k;
61 #endif
63 eq_cnt = 0;
64 for (y=0; y<4; y++) {
65 for (x=1; x<=7; x++) {
66 if (ABS(v[x+y*stride]-v[1+x+y*stride]) <= 1) eq_cnt--;
70 #ifdef PP_SELF_CHECK
71 eq_cnt2 = 0;
72 for (k=0; k<4; k++) {
73 for (j=1; j<=7; j++) {
74 if (ABS(v[j+k*stride]-v[1+j+k*stride]) <= 1) eq_cnt2--;
77 if (eq_cnt2 != eq_cnt) printf("ERROR: C version of useDC is incorrect\n");
78 #endif
80 useDC = eq_cnt <= -DEBLOCK_HORIZ_USEDC_THR;
82 return useDC;
86 /* decide whether the DC filter should be turned on accoding to QP */
87 static int deblock_horiz_DC_on(uint8_t *v, int stride, int QP) {
88 /* 99% of the time, this test turns out the same as the |max-min| strategy in the standard */
89 return (ABS(v[1]-v[8]) < 2*QP);
96 /* The 9-tap low pass filter used in "DC" regions */
97 static void deblock_horiz_lpf9(uint8_t *v, int stride, int QP) {
98 int x, y, p1, p2, psum;
99 uint8_t *vv, vnew[9];
100 #ifdef PP_SELF_CHECK
101 uint8_t selfcheck[9];
102 int psum2;
103 uint8_t *vv2;
104 #endif
106 for (y=0; y<4; y++) {
107 p1 = (ABS(v[0+y*stride]-v[1+y*stride]) < QP ) ? v[0+y*stride] : v[1+y*stride];
108 p2 = (ABS(v[8+y*stride]-v[9+y*stride]) < QP ) ? v[9+y*stride] : v[8+y*stride];
111 #ifdef PP_SELF_CHECK
112 /* generate a self-check version of the filter result in selfcheck[9] */
113 /* low pass filtering (LPF9: 1 1 2 2 4 2 2 1 1) */
114 vv2 = &(v[y*stride]);
115 psum2 = p1 + p1 + p1 + vv2[1] + vv2[2] + vv2[3] + vv2[4] + 4;
116 selfcheck[1] = (((psum2 + vv2[1]) << 1) - (vv2[4] - vv2[5])) >> 4;
117 psum2 += vv2[5] - p1;
118 selfcheck[2] = (((psum2 + vv2[2]) << 1) - (vv2[5] - vv2[6])) >> 4;
119 psum2 += vv2[6] - p1;
120 selfcheck[3] = (((psum2 + vv2[3]) << 1) - (vv2[6] - vv2[7])) >> 4;
121 psum2 += vv2[7] - p1;
122 selfcheck[4] = (((psum2 + vv2[4]) << 1) + p1 - vv2[1] - (vv2[7] - vv2[8])) >> 4;
123 psum2 += vv2[8] - vv2[1];
124 selfcheck[5] = (((psum2 + vv2[5]) << 1) + (vv2[1] - vv2[2]) - vv2[8] + p2) >> 4;
125 psum2 += p2 - vv2[2];
126 selfcheck[6] = (((psum2 + vv2[6]) << 1) + (vv2[2] - vv2[3])) >> 4;
127 psum2 += p2 - vv2[3];
128 selfcheck[7] = (((psum2 + vv2[7]) << 1) + (vv2[3] - vv2[4])) >> 4;
129 psum2 += p2 - vv2[4];
130 selfcheck[8] = (((psum2 + vv2[8]) << 1) + (vv2[4] - vv2[5])) >> 4;
131 #endif
133 /* C implementation of horizontal LPF */
134 vv = &(v[y*stride]);
135 psum = p1 + p1 + p1 + vv[1] + vv[2] + vv[3] + vv[4] + 4;
136 vnew[1] = (((psum + vv[1]) << 1) - (vv[4] - vv[5])) >> 4;
137 psum += vv[5] - p1;
138 vnew[2] = (((psum + vv[2]) << 1) - (vv[5] - vv[6])) >> 4;
139 psum += vv[6] - p1;
140 vnew[3] = (((psum + vv[3]) << 1) - (vv[6] - vv[7])) >> 4;
141 psum += vv[7] - p1;
142 vnew[4] = (((psum + vv[4]) << 1) + p1 - vv[1] - (vv[7] - vv[8])) >> 4;
143 psum += vv[8] - vv[1];
144 vnew[5] = (((psum + vv[5]) << 1) + (vv[1] - vv[2]) - vv[8] + p2) >> 4;
145 psum += p2 - vv[2];
146 vnew[6] = (((psum + vv[6]) << 1) + (vv[2] - vv[3])) >> 4;
147 psum += p2 - vv[3];
148 vnew[7] = (((psum + vv[7]) << 1) + (vv[3] - vv[4])) >> 4;
149 psum += p2 - vv[4];
150 vnew[8] = (((psum + vv[8]) << 1) + (vv[4] - vv[5])) >> 4;
151 for (x=1; x<=8; x++) {
152 vv[x] = vnew[x];
155 #ifdef PP_SELF_CHECK
156 for (x=1; x<=8; x++) {
157 if (selfcheck[x] != v[x+y*stride]) printf("ERROR: C version of horiz lpf9 is incorrect\n");
159 #endif
169 /* horizontal deblocking filter used in default (non-DC) mode */
170 static void deblock_horiz_default_filter(uint8_t *v, int stride, int QP) {
171 int a3_0, a3_1, a3_2, d;
172 int q1, q;
173 int y;
175 for (y=0; y<4; y++) {
177 q1 = v[4] - v[5];
178 q = q1 / 2;
179 if (q) {
181 a3_0 = 2*(v[3]-v[6]) - 5*q1;
183 /* apply the 'delta' function first and check there is a difference to avoid wasting time */
184 if (ABS(a3_0) < 8*QP) {
186 a3_1 = 2*(v[1]-v[4]) + 5*(v[3]-v[2]);
187 a3_2 = 2*(v[5]-v[8]) + 5*(v[7]-v[8]);
188 d = ABS(a3_0) - MIN(ABS(a3_1), ABS(a3_2));
190 if (d > 0) { /* energy across boundary is greater than in one or both of the blocks */
191 d += d<<2;
192 d = (d + 32) >> 6;
194 if (d > 0) {
196 d *= SIGN(-a3_0);
198 /* clip d in the range 0 ... q */
199 if (q > 0) {
200 d = d<0 ? 0 : d;
201 d = d>q ? q : d;
202 } else {
203 d = d>0 ? 0 : d;
204 d = d<q ? q : d;
207 v[4] -= d;
208 v[5] += d;
215 #ifdef PP_SELF_CHECK
216 /* no selfcheck written for this yet */
217 #endif;
219 v += stride;
228 /* this is a horizontal deblocking filter - i.e. it will smooth _vertical_ block edges */
229 void deblock_horiz(uint8_t *image, int width, int height, int stride, QP_STORE_T *QP_store, int QP_stride, int chroma) {
230 int x, y;
231 int QP;
232 uint8_t *v;
233 int useDC, DC_on;
235 /* loop over image's pixel rows , four at a time */
236 for (y=0; y<height; y+=4) {
238 /* loop over every block boundary in that row */
239 for (x=8; x<width; x+=8) {
241 /* extract QP from the decoder's array of QP values */
242 QP = chroma ? QP_store[y/8*QP_stride+x/8]
243 : QP_store[y/16*QP_stride+x/16];
245 /* v points to pixel v0, in the left-hand block */
246 v = &(image[y*stride + x]) - 5;
248 /* first decide whether to use default or DC offet mode */
249 useDC = deblock_horiz_useDC(v, stride);
251 if (useDC) { /* use DC offset mode */
253 DC_on = deblock_horiz_DC_on(v, stride, QP);
255 if (DC_on) {
257 deblock_horiz_lpf9(v, stride, QP);
259 #ifdef SHOWDECISIONS_H
260 if (!chromaFlag) {
261 v[0*stride + 4] =
262 v[1*stride + 4] =
263 v[2*stride + 4] =
264 v[3*stride + 4] = 255;
266 #endif
269 } else { /* use default mode */
271 deblock_horiz_default_filter(v, stride, QP);
273 #ifdef SHOWDECISIONS_H
274 if (!chromaFlag) {
275 v[0*stride + 4] =
276 v[1*stride + 4] =
277 v[2*stride + 4] =
278 v[3*stride + 4] = 0;
280 #endif
291 /***** V E R T I C A L D E B L O C K I N G F I L T E R *****/
294 /* decide DC mode or default mode in assembler */
295 static int deblock_vert_useDC(uint8_t *v, int stride) {
296 int eq_cnt, useDC, x, y;
297 #ifdef PP_SELF_CHECK
298 int useDC2, j, i;
299 #endif
301 #ifdef PP_SELF_CHECK
302 /* C-code version for testing */
303 eq_cnt = 0;
304 for (j=1; j<8; j++) {
305 for (i=0; i<8; i++) {
306 if (ABS(v[j*stride+i] - v[(j+1)*stride+i]) <= 1) eq_cnt++;
309 useDC2 = (eq_cnt > DEBLOCK_VERT_USEDC_THR);
310 #endif
312 /* C-code imlementation of vertial useDC */
313 eq_cnt = 0;
314 for (y=1; y<8; y++) {
315 for (x=0; x<8; x++) {
316 if (ABS(v[y*stride+x] - v[(y+1)*stride+x]) <= 1) eq_cnt++;
319 useDC = (eq_cnt > DEBLOCK_VERT_USEDC_THR);
321 #ifdef PP_SELF_CHECK
322 if (useDC != useDC2) printf("ERROR: C version of useDC is incorrect\n");
323 #endif
325 return useDC;
332 /* decide whether the DC filter should be turned on accoding to QP */
333 static int deblock_vert_DC_on(uint8_t *v, int stride, int QP) {
334 int DC_on, x;
335 #ifdef PP_SELF_CHECK
336 int i, DC_on2;
337 #endif
339 #ifdef PP_SELF_CHECK
340 DC_on2 = 1;
341 for (i=0; i<8; i++) {
342 if (ABS(v[i+1*stride]-v[i+8*stride]) > 2 *QP) DC_on2 = 0;
344 #endif
346 /* C implementation of vertical DC_on */
347 DC_on = 1;
348 for (x=0; x<8; x++) {
349 if (ABS(v[x+1*stride]-v[x+8*stride]) > 2 *QP) DC_on = 0;
352 #ifdef PP_SELF_CHECK
353 if (DC_on != DC_on2) printf("ERROR: C version of DC_on is incorrect\n");
354 #endif
356 return DC_on;
365 /* Vertical 9-tap low-pass filter for use in "DC" regions of the picture */
366 void deblock_vert_lpf9(uint64_t *v_local, uint64_t *p1p2, uint8_t *v, int stride, int QP) {
367 int x, y;
368 int p1, p2, psum;
369 uint8_t *vv, vnew[9];
370 /* define semi-constants to enable us to move up and down the picture easily... */
371 int l1 = 1 * stride;
372 int l2 = 2 * stride;
373 int l3 = 3 * stride;
374 int l4 = 4 * stride;
375 int l5 = 5 * stride;
376 int l6 = 6 * stride;
377 int l7 = 7 * stride;
378 int l8 = 8 * stride;
379 #ifdef PP_SELF_CHECK
380 int j, k;
381 uint8_t selfcheck[64];
382 #endif
385 #ifdef PP_SELF_CHECK
386 /* generate a self-check version of the filter result in selfcheck[64] */
387 for (j=0; j<8; j++) { /* loop left->right */
388 vv = &(v[j]);
389 p1 = (ABS(vv[0*stride]-vv[1*stride]) < QP ) ? vv[0*stride] : vv[1*stride];
390 p2 = (ABS(vv[8*stride]-vv[9*stride]) < QP ) ? vv[9*stride] : vv[8*stride];
391 /* the above may well be endian-fussy */
392 psum = p1 + p1 + p1 + vv[l1] + vv[l2] + vv[l3] + vv[l4] + 4;
393 selfcheck[j+8*0] = (((psum + vv[l1]) << 1) - (vv[l4] - vv[l5])) >> 4;
394 psum += vv[l5] - p1;
395 selfcheck[j+8*1] = (((psum + vv[l2]) << 1) - (vv[l5] - vv[l6])) >> 4;
396 psum += vv[l6] - p1;
397 selfcheck[j+8*2] = (((psum + vv[l3]) << 1) - (vv[l6] - vv[l7])) >> 4;
398 psum += vv[l7] - p1;
399 selfcheck[j+8*3] = (((psum + vv[l4]) << 1) + p1 - vv[l1] - (vv[l7] - vv[l8])) >> 4;
400 psum += vv[l8] - vv[l1];
401 selfcheck[j+8*4] = (((psum + vv[l5]) << 1) + (vv[l1] - vv[l2]) - vv[l8] + p2) >> 4;
402 psum += p2 - vv[l2];
403 selfcheck[j+8*5] = (((psum + vv[l6]) << 1) + (vv[l2] - vv[l3])) >> 4;
404 psum += p2 - vv[l3];
405 selfcheck[j+8*6] = (((psum + vv[l7]) << 1) + (vv[l3] - vv[l4])) >> 4;
406 psum += p2 - vv[l4];
407 selfcheck[j+8*7] = (((psum + vv[l8]) << 1) + (vv[l4] - vv[l5])) >> 4;
409 #endif
411 /* simple C implementation of vertical default filter */
412 for (x=0; x<8; x++) { /* loop left->right */
413 vv = &(v[x]);
414 p1 = (ABS(vv[0*stride]-vv[1*stride]) < QP ) ? vv[0*stride] : vv[1*stride];
415 p2 = (ABS(vv[8*stride]-vv[9*stride]) < QP ) ? vv[9*stride] : vv[8*stride];
416 /* the above may well be endian-fussy */
417 psum = p1 + p1 + p1 + vv[l1] + vv[l2] + vv[l3] + vv[l4] + 4;
418 vnew[1] = (((psum + vv[l1]) << 1) - (vv[l4] - vv[l5])) >> 4;
419 psum += vv[l5] - p1;
420 vnew[2] = (((psum + vv[l2]) << 1) - (vv[l5] - vv[l6])) >> 4;
421 psum += vv[l6] - p1;
422 vnew[3] = (((psum + vv[l3]) << 1) - (vv[l6] - vv[l7])) >> 4;
423 psum += vv[l7] - p1;
424 vnew[4] = (((psum + vv[l4]) << 1) + p1 - vv[l1] - (vv[l7] - vv[l8])) >> 4;
425 psum += vv[l8] - vv[l1];
426 vnew[5] = (((psum + vv[l5]) << 1) + (vv[l1] - vv[l2]) - vv[l8] + p2) >> 4;
427 psum += p2 - vv[l2];
428 vnew[6] = (((psum + vv[l6]) << 1) + (vv[l2] - vv[l3])) >> 4;
429 psum += p2 - vv[l3];
430 vnew[7] = (((psum + vv[l7]) << 1) + (vv[l3] - vv[l4])) >> 4;
431 psum += p2 - vv[l4];
432 vnew[8] = (((psum + vv[l8]) << 1) + (vv[l4] - vv[l5])) >> 4;
433 for (y=1; y<=8; y++) {
434 vv[y*stride] = vnew[y];
438 #ifdef PP_SELF_CHECK
439 /* use the self-check version of the filter result in selfcheck[64] to verify the filter output */
440 for (k=0; k<8; k++) { /* loop top->bottom */
441 for (j=0; j<8; j++) { /* loop left->right */
442 if (v[(k+1)*stride + j] != selfcheck[j+8*k]) printf("ERROR: problem with C filter in row %d\n", k+1);
445 #endif
452 /* Vertical deblocking filter for use in non-flat picture regions */
453 static void deblock_vert_default_filter(uint8_t *v, int stride, int QP) {
454 int x, a3_0, a3_1, a3_2, d, q;
455 /* define semi-constants to enable us to move up and down the picture easily... */
456 int l1 = 1 * stride;
457 int l2 = 2 * stride;
458 int l3 = 3 * stride;
459 int l4 = 4 * stride;
460 int l5 = 5 * stride;
461 int l6 = 6 * stride;
462 int l7 = 7 * stride;
463 int l8 = 8 * stride;
465 #ifdef PP_SELF_CHECK
466 int j, k, a3_0_SC, a3_1_SC, a3_2_SC, d_SC, q_SC;
467 uint8_t selfcheck[8][2];
468 #endif
470 #ifdef PP_SELF_CHECK
471 /* compute selfcheck matrix for later comparison */
472 for (j=0; j<8; j++) {
473 a3_0_SC = 2*v[l3+j] - 5*v[l4+j] + 5*v[l5+j] - 2*v[l6+j];
474 a3_1_SC = 2*v[l1+j] - 5*v[l2+j] + 5*v[l3+j] - 2*v[l4+j];
475 a3_2_SC = 2*v[l5+j] - 5*v[l6+j] + 5*v[l7+j] - 2*v[l8+j];
476 q_SC = (v[l4+j] - v[l5+j]) / 2;
478 if (ABS(a3_0_SC) < 8*QP) {
480 d_SC = ABS(a3_0_SC) - MIN(ABS(a3_1_SC), ABS(a3_2_SC));
481 if (d_SC < 0) d_SC=0;
483 d_SC = (5*d_SC + 32) >> 6;
484 d_SC *= SIGN(-a3_0_SC);
486 //printf("d_SC[%d] preclip=%d\n", j, d_SC);
487 /* clip d in the range 0 ... q */
488 if (q_SC > 0) {
489 d_SC = d_SC<0 ? 0 : d_SC;
490 d_SC = d_SC>q_SC ? q_SC : d_SC;
491 } else {
492 d_SC = d_SC>0 ? 0 : d_SC;
493 d_SC = d_SC<q_SC ? q_SC : d_SC;
496 } else {
497 d_SC = 0;
499 selfcheck[j][0] = v[l4+j] - d_SC;
500 selfcheck[j][1] = v[l5+j] + d_SC;
502 #endif
504 /* simple C implementation of vertical default filter */
505 for (x=0; x<8; x++) {
506 a3_0 = 2*v[l3+x] - 5*v[l4+x] + 5*v[l5+x] - 2*v[l6+x];
507 a3_1 = 2*v[l1+x] - 5*v[l2+x] + 5*v[l3+x] - 2*v[l4+x];
508 a3_2 = 2*v[l5+x] - 5*v[l6+x] + 5*v[l7+x] - 2*v[l8+x];
509 q = (v[l4+x] - v[l5+x]) / 2;
511 if (ABS(a3_0) < 8*QP) {
513 d = ABS(a3_0) - MIN(ABS(a3_1), ABS(a3_2));
514 if (d < 0) d=0;
516 d = (5*d + 32) >> 6;
517 d *= SIGN(-a3_0);
519 //printf("d[%d] preclip=%d\n", x, d);
520 /* clip d in the range 0 ... q */
521 if (q > 0) {
522 d = d<0 ? 0 : d;
523 d = d>q ? q : d;
524 } else {
525 d = d>0 ? 0 : d;
526 d = d<q ? q : d;
529 } else {
530 d = 0;
532 v[l4+x] -= d;
533 v[l5+x] += d;
540 #ifdef PP_SELF_CHECK
541 /* do selfcheck */
542 for (j=0; j<8; j++) {
543 for (k=0; k<2; k++) {
544 if (selfcheck[j][k] != v[l4+j+k*stride]) {
545 printf("ERROR: problem with vertical default filter in col %d, row %d\n", j, k);
546 printf("%d should be %d\n", v[l4+j+k*stride], selfcheck[j][k]);
551 #endif
567 /* this is a vertical deblocking filter - i.e. it will smooth _horizontal_ block edges */
568 void deblock_vert( uint8_t *image, int width, int height, int stride, QP_STORE_T *QP_store, int QP_stride, int chroma) {
569 uint64_t v_local[20];
570 uint64_t p1p2[4];
571 int Bx, y;
572 int QP, QPx16;
573 uint8_t *v;
574 int useDC, DC_on;
576 /* loop over image's block boundary rows */
577 for (y=8; y<height; y+=8) {
579 /* loop over all blocks, left to right */
580 for (Bx=0; Bx<width; Bx+=8) {
582 QP = chroma ? QP_store[y/8*QP_stride+Bx/8]
583 : QP_store[y/16*QP_stride+Bx/16];
584 QPx16 = 16 * QP;
585 v = &(image[y*stride + Bx]) - 5*stride;
587 /* decide whether to use DC mode on a block-by-block basis */
588 useDC = deblock_vert_useDC(v, stride);
590 if (useDC) {
591 /* we are in DC mode for this block. But we only want to filter low-energy areas */
593 /* decide whether the filter should be on or off for this block */
594 DC_on = deblock_vert_DC_on(v, stride, QP);
596 if (DC_on) { /* use DC offset mode */
598 v = &(image[y*stride + Bx])- 5*stride;
600 /* copy the block we're working on and unpack to 16-bit values */
601 /* not needed for plain C version */
602 //deblock_vert_copy_and_unpack(stride, &(v[stride]), &(v_local[2]), 8);
603 //deblock_vert_choose_p1p2(v, stride, p1p2, QP);
605 deblock_vert_lpf9(v_local, p1p2, v, stride, QP);
607 #ifdef SHOWDECISIONS_V
608 if (!chromaFlag) {
609 v[4*stride ] =
610 v[4*stride+1] =
611 v[4*stride+2] =
612 v[4*stride+3] =
613 v[4*stride+4] =
614 v[4*stride+5] =
615 v[4*stride+6] =
616 v[4*stride+7] = 255;
618 #endif
622 if (!useDC) { /* use the default filter */
624 v = &(image[y*stride + Bx])- 5*stride;
626 deblock_vert_default_filter(v, stride, QP);
628 #ifdef SHOWDECISIONS_V
629 if (!chromaFlag) {
630 v[4*stride ] =
631 v[4*stride+1] =
632 v[4*stride+2] =
633 v[4*stride+3] =
634 v[4*stride+4] =
635 v[4*stride+5] =
636 v[4*stride+6] =
637 v[4*stride+7] = 0;
639 #endif
651 /* this is the deringing filter */
652 void dering( uint8_t *image, int width, int height, int stride, QP_STORE_T *QP_store, int QP_stride, int chroma) {
653 int x, y, h, v, i, j;
654 uint8_t *b8x8, *b10x10;
655 uint8_t b8x8filtered[64];
656 int QP, max_diff;
657 uint8_t min, max, thr, range;
658 uint16_t indicesP[10]; /* bitwise array of binary indices above threshold */
659 uint16_t indicesN[10]; /* bitwise array of binary indices below threshold */
660 uint16_t indices3x3[8]; /* bitwise array of pixels where we should filter */
661 uint16_t sr;
663 /* loop over all the 8x8 blocks in the image... */
664 /* don't process outer row of blocks for the time being. */
665 for (y=8; y<height-8; y+=8) {
666 for (x=8; x< width-8; x+=8) {
668 /* QP for this block.. */
669 QP = chroma ? QP_store[y/8*QP_stride+x/8]
670 : QP_store[y/16*QP_stride+x/16];
672 /* pointer to the top left pixel in 8x8 block */
673 b8x8 = &(image[stride*y + x]);
674 /* pointer to the top left pixel in 10x10 block */
675 b10x10 = &(image[stride*(y-1) + (x-1)]);
677 /* Threshold detirmination - find min and max grey levels in the block */
678 min = 255; max = 0;
679 for (v=0; v<8; v++) {
680 for (h=0; h<8; h++) {
681 min = b8x8[stride*v + h] < min ? b8x8[stride*v + h] : min;
682 max = b8x8[stride*v + h] > max ? b8x8[stride*v + h] : max;
685 /* Threshold detirmination - compute threshold and dynamic range */
686 thr = (max + min + 1) / 2;
687 range = max - min;
689 /* Threshold rearrangement not implemented yet */
691 /* Index aquisition */
692 for (j=0; j<10; j++) {
693 indicesP[j] = 0;
694 for (i=0; i<10; i++) {
695 if (b10x10[j*stride+i] >= thr) indicesP[j] |= (2 << i);
697 indicesN[j] = ~indicesP[j];
700 /* Adaptive filtering */
701 /* need to identify 3x3 blocks of '1's in indicesP and indicesN */
702 for (j=0; j<10; j++) {
703 indicesP[j] = (indicesP[j]<<1) & indicesP[j] & (indicesP[j]>>1);
704 indicesN[j] = (indicesN[j]<<1) & indicesN[j] & (indicesN[j]>>1);
706 for (j=1; j<9; j++) {
707 indices3x3[j-1] = indicesP[j-1] & indicesP[j] & indicesP[j+1];
708 indices3x3[j-1] |= indicesN[j-1] & indicesN[j] & indicesN[j+1];
711 for (v=0; v<8; v++) {
712 sr = 4;
713 for (h=0; h<8; h++) {
714 if (indices3x3[v] & sr) {
715 b8x8filtered[8*v + h] = ( 8
716 + 1 * b10x10[stride*(v+0) + (h+0)] + 2 * b10x10[stride*(v+0) + (h+1)] + 1 * b10x10[stride*(v+0) + (h+2)]
717 + 2 * b10x10[stride*(v+1) + (h+0)] + 4 * b10x10[stride*(v+1) + (h+1)] + 2 * b10x10[stride*(v+1) + (h+2)]
718 + 1 * b10x10[stride*(v+2) + (h+0)] + 2 * b10x10[stride*(v+2) + (h+1)] + 1 * b10x10[stride*(v+2) + (h+2)]
719 ) / 16;
721 sr <<= 1;
725 /* Clipping */
726 max_diff = QP/2;
727 for (v=0; v<8; v++) {
728 sr = 4;
729 for (h=0; h<8; h++) {
730 if (indices3x3[v] & sr) {
731 if (b8x8filtered[8*v + h] - b8x8[stride*v + h] > max_diff) {
732 b8x8[stride*v + h] = b8x8[stride*v + h] + max_diff;
733 } else if (b8x8filtered[8*v + h] - b8x8[stride*v + h] < -max_diff) {
734 b8x8[stride*v + h] = b8x8[stride*v + h] - max_diff;
735 } else {
736 b8x8[stride*v + h] = b8x8filtered[8*v + h];
739 sr <<= 1;
753 /* This function is more or less what Andrea wanted: */
754 void postprocess(unsigned char * src[], int src_stride,
755 unsigned char * dst[], int dst_stride,
756 int horizontal_size, int vertical_size,
757 QP_STORE_T *QP_store, int QP_stride,
758 int mode) {
760 uint8_t *Y, *U, *V;
761 int x, y;
763 if (!(mode & PP_DONT_COPY)) {
764 /* First copy source to destination... */
765 /* luma */
766 for (y=0; y<vertical_size; y++) {
767 for (x=0; x<horizontal_size; x++) {
768 (dst[0])[y*dst_stride + x] = (src[0])[y*src_stride + x];
771 /* chroma */
772 for (y=0; y<vertical_size/2; y++) {
773 for (x=0; x<horizontal_size/2; x++) {
774 (dst[1])[y*dst_stride/2 + x] = (src[1])[y*src_stride/2 + x];
775 (dst[2])[y*dst_stride/2 + x] = (src[2])[y*src_stride/2 + x];
780 Y = dst[0];
781 U = dst[1];
782 V = dst[2];
784 if (mode & PP_DEBLOCK_Y_H) {
785 deblock_horiz(Y, horizontal_size, vertical_size, dst_stride, QP_store, QP_stride, 0);
787 if (mode & PP_DEBLOCK_Y_V) {
788 deblock_vert( Y, horizontal_size, vertical_size, dst_stride, QP_store, QP_stride, 0);
790 if (mode & PP_DEBLOCK_C_H) {
791 deblock_horiz(U, horizontal_size/2, vertical_size/2, dst_stride/2, QP_store, QP_stride, 1);
792 deblock_horiz(V, horizontal_size/2, vertical_size/2, dst_stride/2, QP_store, QP_stride, 1);
794 if (mode & PP_DEBLOCK_C_V) {
795 deblock_vert( U, horizontal_size/2, vertical_size/2, dst_stride/2, QP_store, QP_stride, 1);
796 deblock_vert( V, horizontal_size/2, vertical_size/2, dst_stride/2, QP_store, QP_stride, 1);
798 if (mode & PP_DERING_Y) {
799 dering( Y, horizontal_size, vertical_size, dst_stride, QP_store, QP_stride, 0);
801 if (mode & PP_DERING_C) {
802 dering( U, horizontal_size/2, vertical_size/2, dst_stride/2, QP_store, QP_stride, 1);
803 dering( V, horizontal_size/2, vertical_size/2, dst_stride/2, QP_store, QP_stride, 1);