1
/*****************************************************************************
2
* postprocessing_c.c: Post Processing plugin in C
3
*****************************************************************************
4
* Copyright (C) 2001 VideoLAN
5
* $Id: postprocessing_c.c 6961 2004-03-05 17:34:23Z sam $
7
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
9
* This program is free software; you can redistribute it and/or modify
10
* it under the terms of the GNU General Public License as published by
11
* the Free Software Foundation; either version 2 of the License, or
12
* (at your option) any later version.
14
* This program is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
* GNU General Public License for more details.
19
* You should have received a copy of the GNU General Public License
20
* along with this program; if not, write to the Free Software
21
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22
*****************************************************************************/
24
#include <vlc/vlc.h> /* only use uint8_t, uint32_t .... */
26
#include "postprocessing.h"
27
#include "postprocessing_common.h"
29
/*****************************************************************************
31
* Internals functions common to pp_deblock_V and pp_deblock_H
33
*****************************************************************************/
35
/****************************************************************************
36
* pp_deblock_isDC_mode : Check if we will use DC mode or Default mode
37
****************************************************************************
38
* Use constant PP_THR1 and PP_THR2 ( PP_2xTHR1 )
40
* Called for for each pixel on a boundary block when doing deblocking
41
* so need to be fast ...
43
****************************************************************************/
44
static inline int pp_deblock_isDC_mode( uint8_t *p_v )
46
unsigned int i_eq_cnt;
48
/* algo : if ( | v[i] -v[i+1] | <= PP_THR1 ) { i_eq_cnt++; } */
50
if(( ( p_v[0] - p_v[1] + PP_THR1 )&0xffff )<= PP_2xTHR1 ) i_eq_cnt++;
51
if(( ( p_v[1] - p_v[2] + PP_THR1 )&0xffff )<= PP_2xTHR1 ) i_eq_cnt++;
52
if(( ( p_v[2] - p_v[3] + PP_THR1 )&0xffff )<= PP_2xTHR1 ) i_eq_cnt++;
53
if(( ( p_v[3] - p_v[4] + PP_THR1 )&0xffff )<= PP_2xTHR1 ) i_eq_cnt++;
54
if(( ( p_v[4] - p_v[5] + PP_THR1 )&0xffff )<= PP_2xTHR1 ) i_eq_cnt++;
55
if(( ( p_v[5] - p_v[6] + PP_THR1 )&0xffff )<= PP_2xTHR1 ) i_eq_cnt++;
56
if(( ( p_v[6] - p_v[7] + PP_THR1 )&0xffff )<= PP_2xTHR1 ) i_eq_cnt++;
57
if(( ( p_v[7] - p_v[8] + PP_THR1 )&0xffff )<= PP_2xTHR1 ) i_eq_cnt++;
58
if(( ( p_v[8] - p_v[9] + PP_THR1 )&0xffff )<= PP_2xTHR1 ) i_eq_cnt++;
62
for( i =0; i < 9; i++ )
64
if(( ( p_v[i] - p_v[i+1] + PP_THR1 )&0xffff )<= PP_2xTHR1 )
70
return( (i_eq_cnt >= PP_THR2 ) ? 1 : 0 );
73
static inline int pp_deblock_isMinMaxOk( uint8_t *p_v, int i_QP )
77
i_min = i_max = p_v[1];
78
if( i_max < p_v[1] ) i_max = p_v[1];
79
if( i_min > p_v[1] ) i_min = p_v[1];
80
if( i_max < p_v[2] ) i_max = p_v[2];
81
if( i_min > p_v[2] ) i_min = p_v[2];
82
if( i_max < p_v[3] ) i_max = p_v[3];
83
if( i_min > p_v[3] ) i_min = p_v[3];
84
if( i_max < p_v[4] ) i_max = p_v[4];
85
if( i_min > p_v[4] ) i_min = p_v[4];
86
if( i_max < p_v[5] ) i_max = p_v[5];
87
if( i_min > p_v[5] ) i_min = p_v[5];
88
if( i_max < p_v[6] ) i_max = p_v[6];
89
if( i_min > p_v[6] ) i_min = p_v[6];
90
if( i_max < p_v[7] ) i_max = p_v[7];
91
if( i_min > p_v[7] ) i_min = p_v[7];
92
if( i_max < p_v[8] ) i_max = p_v[8];
93
if( i_min > p_v[8] ) i_min = p_v[8];
98
for( i = 2; i < 9; i++ )
100
if( i_max < p_v[i] ) i_max = p_v[i];
101
if( i_min > p_v[i] ) i_min = p_v[i];
103
i_range = i_max - i_min;
105
return( i_max - i_min < 2*i_QP ? 1 : 0 );
109
static inline void pp_deblock_DefaultMode( uint8_t i_v[10], int i_stride,
113
int a3x0, a3x0_, a3x1, a3x2;
116
/* d = CLIP( 5(a3x0' - a3x0)//8, 0, (v4-v5)/2 ).d( abs(a3x0) < QP ) */
118
/* First calculate a3x0 */
119
a3x0 = 2 * ( i_v[3] - i_v[6] ) + 5 *( i_v[5] - i_v[4] );
130
/* XXX Now a3x0 is abs( a3x0 ) */
131
if( ( a3x0 < 8 * i_QP )&&( a3x0 != 0 ) ) /* |a3x0| < 8*i_QP */
133
/* calculate a3x1 et a3x2 */
134
a3x1 = 2 * ( i_v[1] - i_v[4] ) + 5 * ( i_v[3] - i_v[2] );
135
a3x2 = 2 * ( i_v[5] - i_v[8] ) + 5 * ( i_v[7] - i_v[6] );
137
if( a3x1 < 0) a3x1 = -a3x1; /* abs( a3x1 ) */
138
if( a3x2 < 0) a3x2 = -a3x2; /* abs( a3x2 ) */
140
a3x0_ = PP_MIN3( a3x0, a3x1, a3x2 );
142
d = 5 *( a3x0 - a3x0_ ) / 8; /* always > 0 */
144
i_delta = ( i_v[4] - i_v[5] ) / 2;
145
/* clip into [0, i_delta] or [i_delta, 0] */
148
if( !b_neg ) /* since true d has sgn(d) = - sgn( a3x0 ) */
151
if( d < i_delta ) d = i_delta;
160
if( d > i_delta ) d = i_delta;
170
static inline void pp_deblock_DCMode( uint8_t *p_v, /* = int i_v[10] */
178
i_p0 = PP_ABS( p_v[1] - p_v[0] ) < i_QP ? p_v[0] : p_v[1];
179
i_p9 = PP_ABS( p_v[8] - p_v[9] ) < i_QP ? p_v[9] : p_v[8];
181
for( i = 1; i < 9; i++ )
183
v[i] = p_v[i]; /* save 8 pix that will be modified */
186
p_v[1] = ( 6 * i_p0 + 4 * v[1]
187
+ 2 *( v[2] + v[3]) + v[4] + v[5]) >> 4;
189
p_v[2] = ( 4 * i_p0 + 2 * v[1] + 4 * v[2]
190
+ 2 *( v[3] + v[4]) + v[5] + v[6]) >> 4;
192
p_v[3] = ( 2 * i_p0 + 2 * (v[1] + v[2]) + 4 * v[3]
193
+ 2 *( v[4] + v[5]) + v[6] + v[7]) >> 4;
195
p_v[4] = ( i_p0 + v[1] + 2 * (v[2] + v[3]) + 4 * v[4]
196
+ 2 *( v[5] + v[6]) + v[7] + v[8]) >> 4;
198
p_v[5] = ( v[1] + v[2] + 2 * (v[3] + v[4]) + 4 * v[5]
199
+ 2 *( v[6] + v[7]) + v[8] + i_p9) >> 4;
201
p_v[6] = ( v[2] + v[3] + 2 * (v[4] + v[5]) + 4 * v[6]
202
+ 2 *( v[7] + v[8]) + 2 * i_p9) >> 4;
204
p_v[7] = ( v[3] + v[4] + 2 * (v[5] + v[6]) + 4 * v[7]
205
+ 2 * v[8] + 4 * i_p9) >> 4;
207
p_v[8] = ( v[4] + v[5] + 2 * (v[6] + v[7]) + 4 * v[8]
214
/*****************************************************************************/
215
/*---------------------------------------------------------------------------*/
217
/* ---------- filter Vertical lines so follow horizontal edges -------- */
219
/*---------------------------------------------------------------------------*/
220
/*****************************************************************************/
222
void E_( pp_deblock_V )( uint8_t *p_plane,
223
int i_width, int i_height, int i_stride,
224
QT_STORE_T *p_QP_store, int i_QP_stride,
229
int i_QP_scale; /* use to do ( ? >> i_QP_scale ) */
234
i_QP_scale = b_chroma ? 5 : 4 ;
236
for( y = 8; y < i_height - 4; y += 8 )
238
p_v = p_plane + ( y - 5 )* i_stride;
239
for( x = 0; x < i_width; x++ )
241
/* First get 10 vert pix to use them without i_stride */
242
for( i = 0; i < 10; i++ )
244
i_v[i] = p_v[i*i_stride + x];
247
i_QP = p_QP_store[(y>>i_QP_scale)*i_QP_stride+
249
/* XXX QP is for v5 */
250
if( pp_deblock_isDC_mode( i_v ) )
252
if( pp_deblock_isMinMaxOk( i_v, i_QP ) )
254
pp_deblock_DCMode( i_v, i_QP );
259
pp_deblock_DefaultMode( i_v, i_stride, i_QP );
262
/* Copy back, XXX only 1-8 were modified */
263
for( i = 1; i < 9; i++ )
265
p_v[i*i_stride + x] = i_v[i];
273
/*****************************************************************************/
274
/*---------------------------------------------------------------------------*/
276
/* --------- filter Horizontal lines so follow vertical edges -------- */
278
/*---------------------------------------------------------------------------*/
279
/*****************************************************************************/
281
void E_( pp_deblock_H )( uint8_t *p_plane,
282
int i_width, int i_height, int i_stride,
283
QT_STORE_T *p_QP_store, int i_QP_stride,
291
i_QP_scale = b_chroma ? 5 : 4 ;
293
for( y = 0; y < i_height; y++ )
295
p_v = p_plane + y * i_stride - 5;
296
for( x = 8; x < i_width - 4; x += 8 )
298
/* p_v point 5 pix before a block boundary */
299
/* XXX QP is for v5 */
300
i_QP = p_QP_store[(y>>i_QP_scale)*i_QP_stride+
302
if( pp_deblock_isDC_mode( p_v + x ) )
304
if( pp_deblock_isMinMaxOk( p_v+ x, i_QP ) )
306
pp_deblock_DCMode( p_v+x, i_QP );
311
pp_deblock_DefaultMode( p_v+x, i_stride, i_QP );
320
/*****************************************************************************
322
* Internals functions common to pp_Dering_Y pp_Dering_C
324
*****************************************************************************/
326
static inline void pp_dering_MinMax( uint8_t *p_block, int i_stride,
327
int *pi_min, int *pi_max )
332
i_min = 255; i_max = 0;
334
for( y = 0; y < 8; y++ )
336
if( i_min > p_block[0] ) i_min = p_block[0];
337
if( i_max < p_block[0] ) i_max = p_block[0];
338
if( i_min > p_block[1] ) i_min = p_block[1];
339
if( i_max < p_block[1] ) i_max = p_block[1];
340
if( i_min > p_block[2] ) i_min = p_block[2];
341
if( i_max < p_block[2] ) i_max = p_block[2];
342
if( i_min > p_block[3] ) i_min = p_block[3];
343
if( i_max < p_block[3] ) i_max = p_block[3];
344
if( i_min > p_block[4] ) i_min = p_block[4];
345
if( i_max < p_block[4] ) i_max = p_block[4];
346
if( i_min > p_block[5] ) i_min = p_block[5];
347
if( i_max < p_block[5] ) i_max = p_block[5];
348
if( i_min > p_block[6] ) i_min = p_block[6];
349
if( i_max < p_block[6] ) i_max = p_block[6];
350
if( i_min > p_block[7] ) i_min = p_block[7];
351
if( i_max < p_block[7] ) i_max = p_block[7];
354
for( x = 0; x < 8; x++ )
356
if( i_min > p_block[x] ) i_min = p_block[x];
357
if( i_max < p_block[x] ) i_max = p_block[x];
368
static inline void pp_dering_BinIndex( uint8_t *p_block, int i_stride,
369
int i_thr, uint32_t *p_bin )
374
for( y = 0; y < 10; y++ )
377
for( x = 0; x < 10; x++ )
379
if( p_block[x] > i_thr )
384
i_bin |= (~i_bin) << 16; /* for detect also three 0 */
385
*p_bin = i_bin&( i_bin >> 1 )&( i_bin << 1 );
392
static inline void pp_dering_Filter( uint8_t *p_block, int i_stride,
406
for( y = 0; y < 8; y++ )
408
i_bin = p_bin[y] & p_bin[y+1] & p_bin[y+2]; /* To be optimised */
409
i_bin |= i_bin >> 16; /* detect 0 or 1 */
411
for( x = 0; x < 8; x++ )
413
if( i_bin&0x02 ) /* 0x02 since 10 index but want 1-9 */
419
i_f = p_block[x - i_stride - 1] +
420
( p_block[x - i_stride ] << 1)+
421
p_block[x - i_stride + 1] +
423
( p_block[x - 1] << 1 )+
424
( p_block[x ] << 2 )+
425
( p_block[x + 1] << 1 )+
427
p_block[x + i_stride - 1] +
428
( p_block[x + i_stride ] << 1 ) +
429
p_block[x + i_stride + 1];
431
i_f = ( 8 + i_f ) >> 4;
433
/* Clamp this value */
435
if( i_f - p_block[x] > ( i_QP_2 ) )
437
i_flt[y][x] = p_block[x] + i_QP_2;
440
if( i_f - p_block[x] < -i_QP_2 )
442
i_flt[y][x] = p_block[x] - i_QP_2;
451
i_flt[y][x] = p_block[x];
458
for( y = 0; y < 8; y++ )
460
for( x = 0; x < 8; x++ )
462
p_sav[x] = i_flt[y][x];
469
/*****************************************************************************/
470
/*---------------------------------------------------------------------------*/
472
/* ----------------- Dering filter on Y and C blocks ----------------- */
474
/*---------------------------------------------------------------------------*/
475
/*****************************************************************************/
477
void E_( pp_dering_Y )( uint8_t *p_plane,
478
int i_width, int i_height, int i_stride,
479
QT_STORE_T *p_QP_store, int i_QP_stride )
482
int i_max[4], i_min[4], i_range[4];
484
int i_max_range, i_kmax;
485
uint32_t i_bin[4][10];
489
/* We process 4 blocks/loop*/
490
for( y = 8; y < i_height-8; y += 16 )
498
p_block[0] = p_plane + y * i_stride + 8;
499
p_block[1] = p_block[0] + 8;
500
p_block[2] = p_block[0] + ( i_stride << 3 );
501
p_block[3] = p_block[2] + 8;
503
for( x = 8; x < i_width-8; x += 16 )
505
/* 1: Calculate threshold */
506
/* Calculate max/min for each block */
507
pp_dering_MinMax( p_block[0], i_stride, &i_min[0], &i_max[0] );
508
pp_dering_MinMax( p_block[1], i_stride, &i_min[1], &i_max[1] );
509
pp_dering_MinMax( p_block[2], i_stride, &i_min[2], &i_max[2] );
510
pp_dering_MinMax( p_block[3], i_stride, &i_min[3], &i_max[3] );
511
/* Calculate range, max_range and thr */
512
i_max_range = 0; i_kmax = 0;
513
for( k = 0; k <= 4; k++ )
515
i_range[k] = i_max[k] - i_min[k];
516
i_thr[k] = ( i_max[k] + i_min[k] + 1 )/2;
517
if( i_max_range < i_max[k])
519
i_max_range = i_max[k];
523
/* Now rearrange thr */
524
if( i_max_range > 64 )
526
for( k = 1; k < 5; k++ )
528
if( i_range[k] < 16 )
533
if( i_range[k] < 32 )
535
i_thr[k] = i_thr[i_kmax];
541
for( k = 1; k < 5; k++ )
543
if( i_range[k] < 16 )
549
/* 2: Index acquisition 10x10 ! so " -i_stride - 1"*/
550
pp_dering_BinIndex( p_block[0] - i_stride - 1, i_stride,
551
i_thr[0], i_bin[0] );
552
pp_dering_BinIndex( p_block[1] - i_stride - 1, i_stride,
553
i_thr[1], i_bin[1] );
554
pp_dering_BinIndex( p_block[2] - i_stride - 1, i_stride,
555
i_thr[2], i_bin[2] );
556
pp_dering_BinIndex( p_block[3] - i_stride - 1, i_stride,
557
i_thr[3], i_bin[3] );
560
/* 3: adaptive smoothing */
561
/* since we begin at (8,8) QP can be different for each block */
562
p_QP = &( p_QP_store[( y >> 4) * i_QP_stride + (x >> 4)] );
564
pp_dering_Filter( p_block[0], i_stride,
567
pp_dering_Filter( p_block[1], i_stride,
570
pp_dering_Filter( p_block[2], i_stride,
571
i_bin[2], p_QP[i_QP_stride] );
573
pp_dering_Filter( p_block[3], i_stride,
574
i_bin[3], p_QP[i_QP_stride+1] );
585
void E_( pp_dering_C )( uint8_t *p_plane,
586
int i_width, int i_height, int i_stride,
587
QT_STORE_T *p_QP_store, int i_QP_stride )
597
for( y = 8; y < i_height-8; y += 8 )
600
p_block = p_plane + y * i_stride + 8;
601
for( x = 8; x < i_width-8; x += 8 )
604
/* 1: Calculate threshold */
605
/* Calculate max/min for each block */
606
pp_dering_MinMax( p_block, i_stride,
609
i_thr = ( i_max + i_min + 1 )/2;
611
/* 2: Index acquisition 10x10 */
612
/* point on 10x10 in wich we have our 8x8 block */
613
pp_dering_BinIndex( p_block - i_stride -1, i_stride,
617
/* 3: adaptive smoothing */
618
pp_dering_Filter( p_block, i_stride,
620
p_QP_store[(y>>5)*i_QP_stride+ (x>>5)]);