1 /**************************************************************************
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. *
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. *
18 * The complete Open DivX license can be found at *
19 * http://www.projectmayo.com/opendivx/license.php *
21 **************************************************************************/
23 * Copyright (C) 2001 - Project Mayo
27 * DivX Advanced Research Center <darc@projectmayo.com>
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"
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
) {
65 for (x
=1; x
<=7; x
++) {
66 if (ABS(v
[x
+y
*stride
]-v
[1+x
+y
*stride
]) <= 1) eq_cnt
--;
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");
80 useDC
= eq_cnt
<= -DEBLOCK_HORIZ_USEDC_THR
;
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
;
101 uint8_t selfcheck
[9];
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
];
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;
133 /* C implementation of horizontal LPF */
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;
138 vnew
[2] = (((psum
+ vv
[2]) << 1) - (vv
[5] - vv
[6])) >> 4;
140 vnew
[3] = (((psum
+ vv
[3]) << 1) - (vv
[6] - vv
[7])) >> 4;
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;
146 vnew
[6] = (((psum
+ vv
[6]) << 1) + (vv
[2] - vv
[3])) >> 4;
148 vnew
[7] = (((psum
+ vv
[7]) << 1) + (vv
[3] - vv
[4])) >> 4;
150 vnew
[8] = (((psum
+ vv
[8]) << 1) + (vv
[4] - vv
[5])) >> 4;
151 for (x
=1; x
<=8; x
++) {
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");
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
;
175 for (y
=0; y
<4; y
++) {
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 */
198 /* clip d in the range 0 ... q */
216 /* no selfcheck written for this yet */
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
) {
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
);
257 deblock_horiz_lpf9(v
, stride
, QP
);
259 #ifdef SHOWDECISIONS_H
264 v
[3*stride
+ 4] = 255;
269 } else { /* use default mode */
271 deblock_horiz_default_filter(v
, stride
, QP
);
273 #ifdef SHOWDECISIONS_H
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
;
302 /* C-code version for testing */
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
);
312 /* C-code imlementation of vertial useDC */
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
);
322 if (useDC
!= useDC2
) printf("ERROR: C version of useDC is incorrect\n");
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
) {
341 for (i
=0; i
<8; i
++) {
342 if (ABS(v
[i
+1*stride
]-v
[i
+8*stride
]) > 2 *QP
) DC_on2
= 0;
346 /* C implementation of vertical DC_on */
348 for (x
=0; x
<8; x
++) {
349 if (ABS(v
[x
+1*stride
]-v
[x
+8*stride
]) > 2 *QP
) DC_on
= 0;
353 if (DC_on
!= DC_on2
) printf("ERROR: C version of DC_on is incorrect\n");
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
) {
369 uint8_t *vv
, vnew
[9];
370 /* define semi-constants to enable us to move up and down the picture easily... */
381 uint8_t selfcheck
[64];
386 /* generate a self-check version of the filter result in selfcheck[64] */
387 for (j
=0; j
<8; j
++) { /* loop left->right */
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;
395 selfcheck
[j
+8*1] = (((psum
+ vv
[l2
]) << 1) - (vv
[l5
] - vv
[l6
])) >> 4;
397 selfcheck
[j
+8*2] = (((psum
+ vv
[l3
]) << 1) - (vv
[l6
] - vv
[l7
])) >> 4;
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;
403 selfcheck
[j
+8*5] = (((psum
+ vv
[l6
]) << 1) + (vv
[l2
] - vv
[l3
])) >> 4;
405 selfcheck
[j
+8*6] = (((psum
+ vv
[l7
]) << 1) + (vv
[l3
] - vv
[l4
])) >> 4;
407 selfcheck
[j
+8*7] = (((psum
+ vv
[l8
]) << 1) + (vv
[l4
] - vv
[l5
])) >> 4;
411 /* simple C implementation of vertical default filter */
412 for (x
=0; x
<8; x
++) { /* loop left->right */
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;
420 vnew
[2] = (((psum
+ vv
[l2
]) << 1) - (vv
[l5
] - vv
[l6
])) >> 4;
422 vnew
[3] = (((psum
+ vv
[l3
]) << 1) - (vv
[l6
] - vv
[l7
])) >> 4;
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;
428 vnew
[6] = (((psum
+ vv
[l6
]) << 1) + (vv
[l2
] - vv
[l3
])) >> 4;
430 vnew
[7] = (((psum
+ vv
[l7
]) << 1) + (vv
[l3
] - vv
[l4
])) >> 4;
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
];
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);
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... */
466 int j
, k
, a3_0_SC
, a3_1_SC
, a3_2_SC
, d_SC
, q_SC
;
467 uint8_t selfcheck
[8][2];
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 */
489 d_SC
= d_SC
<0 ? 0 : d_SC
;
490 d_SC
= d_SC
>q_SC
? q_SC
: d_SC
;
492 d_SC
= d_SC
>0 ? 0 : d_SC
;
493 d_SC
= d_SC
<q_SC
? q_SC
: d_SC
;
499 selfcheck
[j
][0] = v
[l4
+j
] - d_SC
;
500 selfcheck
[j
][1] = v
[l5
+j
] + d_SC
;
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
));
519 //printf("d[%d] preclip=%d\n", x, d);
520 /* clip d in the range 0 ... q */
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
]);
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];
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];
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
);
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
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
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];
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 */
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 */
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;
689 /* Threshold rearrangement not implemented yet */
691 /* Index aquisition */
692 for (j
=0; j
<10; j
++) {
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
++) {
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)]
727 for (v
=0; v
<8; v
++) {
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
;
736 b8x8
[stride
*v
+ h
] = b8x8filtered
[8*v
+ h
];
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
,
763 if (!(mode
& PP_DONT_COPY
)) {
764 /* First copy source to destination... */
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
];
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
];
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);