]> git.sesse.net Git - ffmpeg/blob - libpostproc/postprocess.c
Merge remote-tracking branch 'qatar/master'
[ffmpeg] / libpostproc / postprocess.c
1 /*
2  * Copyright (C) 2001-2003 Michael Niedermayer (michaelni@gmx.at)
3  *
4  * AltiVec optimizations (C) 2004 Romain Dolbeau <romain@dolbeau.org>
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22
23 /**
24  * @file
25  * postprocessing.
26  */
27
28 /*
29                         C       MMX     MMX2    3DNow   AltiVec
30 isVertDC                Ec      Ec                      Ec
31 isVertMinMaxOk          Ec      Ec                      Ec
32 doVertLowPass           E               e       e       Ec
33 doVertDefFilter         Ec      Ec      e       e       Ec
34 isHorizDC               Ec      Ec                      Ec
35 isHorizMinMaxOk         a       E                       Ec
36 doHorizLowPass          E               e       e       Ec
37 doHorizDefFilter        Ec      Ec      e       e       Ec
38 do_a_deblock            Ec      E       Ec      E
39 deRing                  E               e       e*      Ecp
40 Vertical RKAlgo1        E               a       a
41 Horizontal RKAlgo1                      a       a
42 Vertical X1#            a               E       E
43 Horizontal X1#          a               E       E
44 LinIpolDeinterlace      e               E       E*
45 CubicIpolDeinterlace    a               e       e*
46 LinBlendDeinterlace     e               E       E*
47 MedianDeinterlace#      E       Ec      Ec
48 TempDeNoiser#           E               e       e       Ec
49
50 * I do not have a 3DNow! CPU -> it is untested, but no one said it does not work so it seems to work
51 # more or less selfinvented filters so the exactness is not too meaningful
52 E = Exact implementation
53 e = almost exact implementation (slightly different rounding,...)
54 a = alternative / approximate impl
55 c = checked against the other implementations (-vo md5)
56 p = partially optimized, still some work to do
57 */
58
59 /*
60 TODO:
61 reduce the time wasted on the mem transfer
62 unroll stuff if instructions depend too much on the prior one
63 move YScale thing to the end instead of fixing QP
64 write a faster and higher quality deblocking filter :)
65 make the mainloop more flexible (variable number of blocks at once
66         (the if/else stuff per block is slowing things down)
67 compare the quality & speed of all filters
68 split this huge file
69 optimize c versions
70 try to unroll inner for(x=0 ... loop to avoid these damn if(x ... checks
71 ...
72 */
73
74 //Changelog: use git log
75
76 #include "config.h"
77 #include "libavutil/avutil.h"
78 #include <inttypes.h>
79 #include <stdio.h>
80 #include <stdlib.h>
81 #include <string.h>
82 //#undef HAVE_MMX2
83 //#define HAVE_AMD3DNOW
84 //#undef HAVE_MMX
85 //#undef ARCH_X86
86 //#define DEBUG_BRIGHTNESS
87 #include "postprocess.h"
88 #include "postprocess_internal.h"
89 #include "libavutil/avstring.h"
90
91 unsigned postproc_version(void)
92 {
93     return LIBPOSTPROC_VERSION_INT;
94 }
95
96 const char *postproc_configuration(void)
97 {
98     return FFMPEG_CONFIGURATION;
99 }
100
101 const char *postproc_license(void)
102 {
103 #define LICENSE_PREFIX "libpostproc license: "
104     return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1;
105 }
106
107 #if HAVE_ALTIVEC_H
108 #include <altivec.h>
109 #endif
110
111 #define GET_MODE_BUFFER_SIZE 500
112 #define OPTIONS_ARRAY_SIZE 10
113 #define BLOCK_SIZE 8
114 #define TEMP_STRIDE 8
115 //#define NUM_BLOCKS_AT_ONCE 16 //not used yet
116
117 #if ARCH_X86
118 DECLARE_ASM_CONST(8, uint64_t, w05)= 0x0005000500050005LL;
119 DECLARE_ASM_CONST(8, uint64_t, w04)= 0x0004000400040004LL;
120 DECLARE_ASM_CONST(8, uint64_t, w20)= 0x0020002000200020LL;
121 DECLARE_ASM_CONST(8, uint64_t, b00)= 0x0000000000000000LL;
122 DECLARE_ASM_CONST(8, uint64_t, b01)= 0x0101010101010101LL;
123 DECLARE_ASM_CONST(8, uint64_t, b02)= 0x0202020202020202LL;
124 DECLARE_ASM_CONST(8, uint64_t, b08)= 0x0808080808080808LL;
125 DECLARE_ASM_CONST(8, uint64_t, b80)= 0x8080808080808080LL;
126 #endif
127
128 DECLARE_ASM_CONST(8, int, deringThreshold)= 20;
129
130
131 static struct PPFilter filters[]=
132 {
133     {"hb", "hdeblock",              1, 1, 3, H_DEBLOCK},
134     {"vb", "vdeblock",              1, 2, 4, V_DEBLOCK},
135 /*  {"hr", "rkhdeblock",            1, 1, 3, H_RK1_FILTER},
136     {"vr", "rkvdeblock",            1, 2, 4, V_RK1_FILTER},*/
137     {"h1", "x1hdeblock",            1, 1, 3, H_X1_FILTER},
138     {"v1", "x1vdeblock",            1, 2, 4, V_X1_FILTER},
139     {"ha", "ahdeblock",             1, 1, 3, H_A_DEBLOCK},
140     {"va", "avdeblock",             1, 2, 4, V_A_DEBLOCK},
141     {"dr", "dering",                1, 5, 6, DERING},
142     {"al", "autolevels",            0, 1, 2, LEVEL_FIX},
143     {"lb", "linblenddeint",         1, 1, 4, LINEAR_BLEND_DEINT_FILTER},
144     {"li", "linipoldeint",          1, 1, 4, LINEAR_IPOL_DEINT_FILTER},
145     {"ci", "cubicipoldeint",        1, 1, 4, CUBIC_IPOL_DEINT_FILTER},
146     {"md", "mediandeint",           1, 1, 4, MEDIAN_DEINT_FILTER},
147     {"fd", "ffmpegdeint",           1, 1, 4, FFMPEG_DEINT_FILTER},
148     {"l5", "lowpass5",              1, 1, 4, LOWPASS5_DEINT_FILTER},
149     {"tn", "tmpnoise",              1, 7, 8, TEMP_NOISE_FILTER},
150     {"fq", "forcequant",            1, 0, 0, FORCE_QUANT},
151     {NULL, NULL,0,0,0,0} //End Marker
152 };
153
154 static const char *replaceTable[]=
155 {
156     "default",      "hb:a,vb:a,dr:a",
157     "de",           "hb:a,vb:a,dr:a",
158     "fast",         "h1:a,v1:a,dr:a",
159     "fa",           "h1:a,v1:a,dr:a",
160     "ac",           "ha:a:128:7,va:a,dr:a",
161     NULL //End Marker
162 };
163
164
165 #if ARCH_X86
166 static inline void prefetchnta(void *p)
167 {
168     __asm__ volatile(   "prefetchnta (%0)\n\t"
169         : : "r" (p)
170     );
171 }
172
173 static inline void prefetcht0(void *p)
174 {
175     __asm__ volatile(   "prefetcht0 (%0)\n\t"
176         : : "r" (p)
177     );
178 }
179
180 static inline void prefetcht1(void *p)
181 {
182     __asm__ volatile(   "prefetcht1 (%0)\n\t"
183         : : "r" (p)
184     );
185 }
186
187 static inline void prefetcht2(void *p)
188 {
189     __asm__ volatile(   "prefetcht2 (%0)\n\t"
190         : : "r" (p)
191     );
192 }
193 #endif
194
195 /* The horizontal functions exist only in C because the MMX
196  * code is faster with vertical filters and transposing. */
197
198 /**
199  * Check if the given 8x8 Block is mostly "flat"
200  */
201 static inline int isHorizDC_C(uint8_t src[], int stride, PPContext *c)
202 {
203     int numEq= 0;
204     int y;
205     const int dcOffset= ((c->nonBQP*c->ppMode.baseDcDiff)>>8) + 1;
206     const int dcThreshold= dcOffset*2 + 1;
207
208     for(y=0; y<BLOCK_SIZE; y++){
209         if(((unsigned)(src[0] - src[1] + dcOffset)) < dcThreshold) numEq++;
210         if(((unsigned)(src[1] - src[2] + dcOffset)) < dcThreshold) numEq++;
211         if(((unsigned)(src[2] - src[3] + dcOffset)) < dcThreshold) numEq++;
212         if(((unsigned)(src[3] - src[4] + dcOffset)) < dcThreshold) numEq++;
213         if(((unsigned)(src[4] - src[5] + dcOffset)) < dcThreshold) numEq++;
214         if(((unsigned)(src[5] - src[6] + dcOffset)) < dcThreshold) numEq++;
215         if(((unsigned)(src[6] - src[7] + dcOffset)) < dcThreshold) numEq++;
216         src+= stride;
217     }
218     return numEq > c->ppMode.flatnessThreshold;
219 }
220
221 /**
222  * Check if the middle 8x8 Block in the given 8x16 block is flat
223  */
224 static inline int isVertDC_C(uint8_t src[], int stride, PPContext *c)
225 {
226     int numEq= 0;
227     int y;
228     const int dcOffset= ((c->nonBQP*c->ppMode.baseDcDiff)>>8) + 1;
229     const int dcThreshold= dcOffset*2 + 1;
230
231     src+= stride*4; // src points to begin of the 8x8 Block
232     for(y=0; y<BLOCK_SIZE-1; y++){
233         if(((unsigned)(src[0] - src[0+stride] + dcOffset)) < dcThreshold) numEq++;
234         if(((unsigned)(src[1] - src[1+stride] + dcOffset)) < dcThreshold) numEq++;
235         if(((unsigned)(src[2] - src[2+stride] + dcOffset)) < dcThreshold) numEq++;
236         if(((unsigned)(src[3] - src[3+stride] + dcOffset)) < dcThreshold) numEq++;
237         if(((unsigned)(src[4] - src[4+stride] + dcOffset)) < dcThreshold) numEq++;
238         if(((unsigned)(src[5] - src[5+stride] + dcOffset)) < dcThreshold) numEq++;
239         if(((unsigned)(src[6] - src[6+stride] + dcOffset)) < dcThreshold) numEq++;
240         if(((unsigned)(src[7] - src[7+stride] + dcOffset)) < dcThreshold) numEq++;
241         src+= stride;
242     }
243     return numEq > c->ppMode.flatnessThreshold;
244 }
245
246 static inline int isHorizMinMaxOk_C(uint8_t src[], int stride, int QP)
247 {
248     int i;
249 #if 1
250     for(i=0; i<2; i++){
251         if((unsigned)(src[0] - src[5] + 2*QP) > 4*QP) return 0;
252         src += stride;
253         if((unsigned)(src[2] - src[7] + 2*QP) > 4*QP) return 0;
254         src += stride;
255         if((unsigned)(src[4] - src[1] + 2*QP) > 4*QP) return 0;
256         src += stride;
257         if((unsigned)(src[6] - src[3] + 2*QP) > 4*QP) return 0;
258         src += stride;
259     }
260 #else
261     for(i=0; i<8; i++){
262         if((unsigned)(src[0] - src[7] + 2*QP) > 4*QP) return 0;
263         src += stride;
264     }
265 #endif
266     return 1;
267 }
268
269 static inline int isVertMinMaxOk_C(uint8_t src[], int stride, int QP)
270 {
271 #if 1
272 #if 1
273     int x;
274     src+= stride*4;
275     for(x=0; x<BLOCK_SIZE; x+=4){
276         if((unsigned)(src[  x + 0*stride] - src[  x + 5*stride] + 2*QP) > 4*QP) return 0;
277         if((unsigned)(src[1+x + 2*stride] - src[1+x + 7*stride] + 2*QP) > 4*QP) return 0;
278         if((unsigned)(src[2+x + 4*stride] - src[2+x + 1*stride] + 2*QP) > 4*QP) return 0;
279         if((unsigned)(src[3+x + 6*stride] - src[3+x + 3*stride] + 2*QP) > 4*QP) return 0;
280     }
281 #else
282     int x;
283     src+= stride*3;
284     for(x=0; x<BLOCK_SIZE; x++){
285         if((unsigned)(src[x + stride] - src[x + (stride<<3)] + 2*QP) > 4*QP) return 0;
286     }
287 #endif
288     return 1;
289 #else
290     int x;
291     src+= stride*4;
292     for(x=0; x<BLOCK_SIZE; x++){
293         int min=255;
294         int max=0;
295         int y;
296         for(y=0; y<8; y++){
297             int v= src[x + y*stride];
298             if(v>max) max=v;
299             if(v<min) min=v;
300         }
301         if(max-min > 2*QP) return 0;
302     }
303     return 1;
304 #endif
305 }
306
307 static inline int horizClassify_C(uint8_t src[], int stride, PPContext *c)
308 {
309     if( isHorizDC_C(src, stride, c) ){
310         if( isHorizMinMaxOk_C(src, stride, c->QP) )
311             return 1;
312         else
313             return 0;
314     }else{
315         return 2;
316     }
317 }
318
319 static inline int vertClassify_C(uint8_t src[], int stride, PPContext *c)
320 {
321     if( isVertDC_C(src, stride, c) ){
322         if( isVertMinMaxOk_C(src, stride, c->QP) )
323             return 1;
324         else
325             return 0;
326     }else{
327         return 2;
328     }
329 }
330
331 static inline void doHorizDefFilter_C(uint8_t dst[], int stride, PPContext *c)
332 {
333     int y;
334     for(y=0; y<BLOCK_SIZE; y++){
335         const int middleEnergy= 5*(dst[4] - dst[3]) + 2*(dst[2] - dst[5]);
336
337         if(FFABS(middleEnergy) < 8*c->QP){
338             const int q=(dst[3] - dst[4])/2;
339             const int leftEnergy=  5*(dst[2] - dst[1]) + 2*(dst[0] - dst[3]);
340             const int rightEnergy= 5*(dst[6] - dst[5]) + 2*(dst[4] - dst[7]);
341
342             int d= FFABS(middleEnergy) - FFMIN( FFABS(leftEnergy), FFABS(rightEnergy) );
343             d= FFMAX(d, 0);
344
345             d= (5*d + 32) >> 6;
346             d*= FFSIGN(-middleEnergy);
347
348             if(q>0)
349             {
350                 d= d<0 ? 0 : d;
351                 d= d>q ? q : d;
352             }
353             else
354             {
355                 d= d>0 ? 0 : d;
356                 d= d<q ? q : d;
357             }
358
359             dst[3]-= d;
360             dst[4]+= d;
361         }
362         dst+= stride;
363     }
364 }
365
366 /**
367  * Do a horizontal low pass filter on the 10x8 block (dst points to middle 8x8 Block)
368  * using the 9-Tap Filter (1,1,2,2,4,2,2,1,1)/16 (C version)
369  */
370 static inline void doHorizLowPass_C(uint8_t dst[], int stride, PPContext *c)
371 {
372     int y;
373     for(y=0; y<BLOCK_SIZE; y++){
374         const int first= FFABS(dst[-1] - dst[0]) < c->QP ? dst[-1] : dst[0];
375         const int last= FFABS(dst[8] - dst[7]) < c->QP ? dst[8] : dst[7];
376
377         int sums[10];
378         sums[0] = 4*first + dst[0] + dst[1] + dst[2] + 4;
379         sums[1] = sums[0] - first  + dst[3];
380         sums[2] = sums[1] - first  + dst[4];
381         sums[3] = sums[2] - first  + dst[5];
382         sums[4] = sums[3] - first  + dst[6];
383         sums[5] = sums[4] - dst[0] + dst[7];
384         sums[6] = sums[5] - dst[1] + last;
385         sums[7] = sums[6] - dst[2] + last;
386         sums[8] = sums[7] - dst[3] + last;
387         sums[9] = sums[8] - dst[4] + last;
388
389         dst[0]= (sums[0] + sums[2] + 2*dst[0])>>4;
390         dst[1]= (sums[1] + sums[3] + 2*dst[1])>>4;
391         dst[2]= (sums[2] + sums[4] + 2*dst[2])>>4;
392         dst[3]= (sums[3] + sums[5] + 2*dst[3])>>4;
393         dst[4]= (sums[4] + sums[6] + 2*dst[4])>>4;
394         dst[5]= (sums[5] + sums[7] + 2*dst[5])>>4;
395         dst[6]= (sums[6] + sums[8] + 2*dst[6])>>4;
396         dst[7]= (sums[7] + sums[9] + 2*dst[7])>>4;
397
398         dst+= stride;
399     }
400 }
401
402 /**
403  * Experimental Filter 1 (Horizontal)
404  * will not damage linear gradients
405  * Flat blocks should look like they were passed through the (1,1,2,2,4,2,2,1,1) 9-Tap filter
406  * can only smooth blocks at the expected locations (it cannot smooth them if they did move)
407  * MMX2 version does correct clipping C version does not
408  * not identical with the vertical one
409  */
410 static inline void horizX1Filter(uint8_t *src, int stride, int QP)
411 {
412     int y;
413     static uint64_t *lut= NULL;
414     if(lut==NULL)
415     {
416         int i;
417         lut = av_malloc(256*8);
418         for(i=0; i<256; i++)
419         {
420             int v= i < 128 ? 2*i : 2*(i-256);
421 /*
422 //Simulate 112242211 9-Tap filter
423             uint64_t a= (v/16)  & 0xFF;
424             uint64_t b= (v/8)   & 0xFF;
425             uint64_t c= (v/4)   & 0xFF;
426             uint64_t d= (3*v/8) & 0xFF;
427 */
428 //Simulate piecewise linear interpolation
429             uint64_t a= (v/16)   & 0xFF;
430             uint64_t b= (v*3/16) & 0xFF;
431             uint64_t c= (v*5/16) & 0xFF;
432             uint64_t d= (7*v/16) & 0xFF;
433             uint64_t A= (0x100 - a)&0xFF;
434             uint64_t B= (0x100 - b)&0xFF;
435             uint64_t C= (0x100 - c)&0xFF;
436             uint64_t D= (0x100 - c)&0xFF;
437
438             lut[i]   = (a<<56) | (b<<48) | (c<<40) | (d<<32) |
439                        (D<<24) | (C<<16) | (B<<8)  | (A);
440             //lut[i] = (v<<32) | (v<<24);
441         }
442     }
443
444     for(y=0; y<BLOCK_SIZE; y++){
445         int a= src[1] - src[2];
446         int b= src[3] - src[4];
447         int c= src[5] - src[6];
448
449         int d= FFMAX(FFABS(b) - (FFABS(a) + FFABS(c))/2, 0);
450
451         if(d < QP){
452             int v = d * FFSIGN(-b);
453
454             src[1] +=v/8;
455             src[2] +=v/4;
456             src[3] +=3*v/8;
457             src[4] -=3*v/8;
458             src[5] -=v/4;
459             src[6] -=v/8;
460         }
461         src+=stride;
462     }
463 }
464
465 /**
466  * accurate deblock filter
467  */
468 static av_always_inline void do_a_deblock_C(uint8_t *src, int step, int stride, PPContext *c){
469     int y;
470     const int QP= c->QP;
471     const int dcOffset= ((c->nonBQP*c->ppMode.baseDcDiff)>>8) + 1;
472     const int dcThreshold= dcOffset*2 + 1;
473 //START_TIMER
474     src+= step*4; // src points to begin of the 8x8 Block
475     for(y=0; y<8; y++){
476         int numEq= 0;
477
478         if(((unsigned)(src[-1*step] - src[0*step] + dcOffset)) < dcThreshold) numEq++;
479         if(((unsigned)(src[ 0*step] - src[1*step] + dcOffset)) < dcThreshold) numEq++;
480         if(((unsigned)(src[ 1*step] - src[2*step] + dcOffset)) < dcThreshold) numEq++;
481         if(((unsigned)(src[ 2*step] - src[3*step] + dcOffset)) < dcThreshold) numEq++;
482         if(((unsigned)(src[ 3*step] - src[4*step] + dcOffset)) < dcThreshold) numEq++;
483         if(((unsigned)(src[ 4*step] - src[5*step] + dcOffset)) < dcThreshold) numEq++;
484         if(((unsigned)(src[ 5*step] - src[6*step] + dcOffset)) < dcThreshold) numEq++;
485         if(((unsigned)(src[ 6*step] - src[7*step] + dcOffset)) < dcThreshold) numEq++;
486         if(((unsigned)(src[ 7*step] - src[8*step] + dcOffset)) < dcThreshold) numEq++;
487         if(numEq > c->ppMode.flatnessThreshold){
488             int min, max, x;
489
490             if(src[0] > src[step]){
491                 max= src[0];
492                 min= src[step];
493             }else{
494                 max= src[step];
495                 min= src[0];
496             }
497             for(x=2; x<8; x+=2){
498                 if(src[x*step] > src[(x+1)*step]){
499                         if(src[x    *step] > max) max= src[ x   *step];
500                         if(src[(x+1)*step] < min) min= src[(x+1)*step];
501                 }else{
502                         if(src[(x+1)*step] > max) max= src[(x+1)*step];
503                         if(src[ x   *step] < min) min= src[ x   *step];
504                 }
505             }
506             if(max-min < 2*QP){
507                 const int first= FFABS(src[-1*step] - src[0]) < QP ? src[-1*step] : src[0];
508                 const int last= FFABS(src[8*step] - src[7*step]) < QP ? src[8*step] : src[7*step];
509
510                 int sums[10];
511                 sums[0] = 4*first + src[0*step] + src[1*step] + src[2*step] + 4;
512                 sums[1] = sums[0] - first       + src[3*step];
513                 sums[2] = sums[1] - first       + src[4*step];
514                 sums[3] = sums[2] - first       + src[5*step];
515                 sums[4] = sums[3] - first       + src[6*step];
516                 sums[5] = sums[4] - src[0*step] + src[7*step];
517                 sums[6] = sums[5] - src[1*step] + last;
518                 sums[7] = sums[6] - src[2*step] + last;
519                 sums[8] = sums[7] - src[3*step] + last;
520                 sums[9] = sums[8] - src[4*step] + last;
521
522                 src[0*step]= (sums[0] + sums[2] + 2*src[0*step])>>4;
523                 src[1*step]= (sums[1] + sums[3] + 2*src[1*step])>>4;
524                 src[2*step]= (sums[2] + sums[4] + 2*src[2*step])>>4;
525                 src[3*step]= (sums[3] + sums[5] + 2*src[3*step])>>4;
526                 src[4*step]= (sums[4] + sums[6] + 2*src[4*step])>>4;
527                 src[5*step]= (sums[5] + sums[7] + 2*src[5*step])>>4;
528                 src[6*step]= (sums[6] + sums[8] + 2*src[6*step])>>4;
529                 src[7*step]= (sums[7] + sums[9] + 2*src[7*step])>>4;
530             }
531         }else{
532             const int middleEnergy= 5*(src[4*step] - src[3*step]) + 2*(src[2*step] - src[5*step]);
533
534             if(FFABS(middleEnergy) < 8*QP){
535                 const int q=(src[3*step] - src[4*step])/2;
536                 const int leftEnergy=  5*(src[2*step] - src[1*step]) + 2*(src[0*step] - src[3*step]);
537                 const int rightEnergy= 5*(src[6*step] - src[5*step]) + 2*(src[4*step] - src[7*step]);
538
539                 int d= FFABS(middleEnergy) - FFMIN( FFABS(leftEnergy), FFABS(rightEnergy) );
540                 d= FFMAX(d, 0);
541
542                 d= (5*d + 32) >> 6;
543                 d*= FFSIGN(-middleEnergy);
544
545                 if(q>0){
546                     d= d<0 ? 0 : d;
547                     d= d>q ? q : d;
548                 }else{
549                     d= d>0 ? 0 : d;
550                     d= d<q ? q : d;
551                 }
552
553                 src[3*step]-= d;
554                 src[4*step]+= d;
555             }
556         }
557
558         src += stride;
559     }
560 /*if(step==16){
561     STOP_TIMER("step16")
562 }else{
563     STOP_TIMER("stepX")
564 }*/
565 }
566
567 //Note: we have C, MMX, MMX2, 3DNOW version there is no 3DNOW+MMX2 one
568 //Plain C versions
569 #if !(HAVE_MMX || HAVE_ALTIVEC) || CONFIG_RUNTIME_CPUDETECT
570 #define COMPILE_C
571 #endif
572
573 #if HAVE_ALTIVEC
574 #define COMPILE_ALTIVEC
575 #endif //HAVE_ALTIVEC
576
577 #if ARCH_X86
578
579 #if (HAVE_MMX && !HAVE_AMD3DNOW && !HAVE_MMX2) || CONFIG_RUNTIME_CPUDETECT
580 #define COMPILE_MMX
581 #endif
582
583 #if HAVE_MMX2 || CONFIG_RUNTIME_CPUDETECT
584 #define COMPILE_MMX2
585 #endif
586
587 #if (HAVE_AMD3DNOW && !HAVE_MMX2) || CONFIG_RUNTIME_CPUDETECT
588 #define COMPILE_3DNOW
589 #endif
590 #endif /* ARCH_X86 */
591
592 #undef HAVE_MMX
593 #define HAVE_MMX 0
594 #undef HAVE_MMX2
595 #define HAVE_MMX2 0
596 #undef HAVE_AMD3DNOW
597 #define HAVE_AMD3DNOW 0
598 #undef HAVE_ALTIVEC
599 #define HAVE_ALTIVEC 0
600
601 #ifdef COMPILE_C
602 #define RENAME(a) a ## _C
603 #include "postprocess_template.c"
604 #endif
605
606 #ifdef COMPILE_ALTIVEC
607 #undef RENAME
608 #undef HAVE_ALTIVEC
609 #define HAVE_ALTIVEC 1
610 #define RENAME(a) a ## _altivec
611 #include "postprocess_altivec_template.c"
612 #include "postprocess_template.c"
613 #endif
614
615 //MMX versions
616 #ifdef COMPILE_MMX
617 #undef RENAME
618 #undef HAVE_MMX
619 #define HAVE_MMX 1
620 #define RENAME(a) a ## _MMX
621 #include "postprocess_template.c"
622 #endif
623
624 //MMX2 versions
625 #ifdef COMPILE_MMX2
626 #undef RENAME
627 #undef HAVE_MMX
628 #undef HAVE_MMX2
629 #define HAVE_MMX 1
630 #define HAVE_MMX2 1
631 #define RENAME(a) a ## _MMX2
632 #include "postprocess_template.c"
633 #endif
634
635 //3DNOW versions
636 #ifdef COMPILE_3DNOW
637 #undef RENAME
638 #undef HAVE_MMX
639 #undef HAVE_MMX2
640 #undef HAVE_AMD3DNOW
641 #define HAVE_MMX 1
642 #define HAVE_MMX2 0
643 #define HAVE_AMD3DNOW 1
644 #define RENAME(a) a ## _3DNow
645 #include "postprocess_template.c"
646 #endif
647
648 // minor note: the HAVE_xyz is messed up after that line so do not use it.
649
650 static inline void postProcess(const uint8_t src[], int srcStride, uint8_t dst[], int dstStride, int width, int height,
651         const QP_STORE_T QPs[], int QPStride, int isColor, pp_mode *vm, pp_context *vc)
652 {
653     PPContext *c= (PPContext *)vc;
654     PPMode *ppMode= (PPMode *)vm;
655     c->ppMode= *ppMode; //FIXME
656
657     // Using ifs here as they are faster than function pointers although the
658     // difference would not be measurable here but it is much better because
659     // someone might exchange the CPU whithout restarting MPlayer ;)
660 #if CONFIG_RUNTIME_CPUDETECT
661 #if ARCH_X86
662     // ordered per speed fastest first
663     if(c->cpuCaps & PP_CPU_CAPS_MMX2)
664         postProcess_MMX2(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
665     else if(c->cpuCaps & PP_CPU_CAPS_3DNOW)
666         postProcess_3DNow(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
667     else if(c->cpuCaps & PP_CPU_CAPS_MMX)
668         postProcess_MMX(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
669     else
670         postProcess_C(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
671 #else
672 #if HAVE_ALTIVEC
673     if(c->cpuCaps & PP_CPU_CAPS_ALTIVEC)
674             postProcess_altivec(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
675     else
676 #endif
677             postProcess_C(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
678 #endif
679 #else //CONFIG_RUNTIME_CPUDETECT
680 #if   HAVE_MMX2
681             postProcess_MMX2(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
682 #elif HAVE_AMD3DNOW
683             postProcess_3DNow(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
684 #elif HAVE_MMX
685             postProcess_MMX(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
686 #elif HAVE_ALTIVEC
687             postProcess_altivec(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
688 #else
689             postProcess_C(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
690 #endif
691 #endif //!CONFIG_RUNTIME_CPUDETECT
692 }
693
694 //static void postProcess(uint8_t src[], int srcStride, uint8_t dst[], int dstStride, int width, int height,
695 //        QP_STORE_T QPs[], int QPStride, int isColor, struct PPMode *ppMode);
696
697 /* -pp Command line Help
698 */
699 #if LIBPOSTPROC_VERSION_INT < (52<<16)
700 const char *const pp_help=
701 #else
702 const char pp_help[] =
703 #endif
704 "Available postprocessing filters:\n"
705 "Filters                        Options\n"
706 "short  long name       short   long option     Description\n"
707 "*      *               a       autoq           CPU power dependent enabler\n"
708 "                       c       chrom           chrominance filtering enabled\n"
709 "                       y       nochrom         chrominance filtering disabled\n"
710 "                       n       noluma          luma filtering disabled\n"
711 "hb     hdeblock        (2 threshold)           horizontal deblocking filter\n"
712 "       1. difference factor: default=32, higher -> more deblocking\n"
713 "       2. flatness threshold: default=39, lower -> more deblocking\n"
714 "                       the h & v deblocking filters share these\n"
715 "                       so you can't set different thresholds for h / v\n"
716 "vb     vdeblock        (2 threshold)           vertical deblocking filter\n"
717 "ha     hadeblock       (2 threshold)           horizontal deblocking filter\n"
718 "va     vadeblock       (2 threshold)           vertical deblocking filter\n"
719 "h1     x1hdeblock                              experimental h deblock filter 1\n"
720 "v1     x1vdeblock                              experimental v deblock filter 1\n"
721 "dr     dering                                  deringing filter\n"
722 "al     autolevels                              automatic brightness / contrast\n"
723 "                       f        fullyrange     stretch luminance to (0..255)\n"
724 "lb     linblenddeint                           linear blend deinterlacer\n"
725 "li     linipoldeint                            linear interpolating deinterlace\n"
726 "ci     cubicipoldeint                          cubic interpolating deinterlacer\n"
727 "md     mediandeint                             median deinterlacer\n"
728 "fd     ffmpegdeint                             ffmpeg deinterlacer\n"
729 "l5     lowpass5                                FIR lowpass deinterlacer\n"
730 "de     default                                 hb:a,vb:a,dr:a\n"
731 "fa     fast                                    h1:a,v1:a,dr:a\n"
732 "ac                                             ha:a:128:7,va:a,dr:a\n"
733 "tn     tmpnoise        (3 threshold)           temporal noise reducer\n"
734 "                     1. <= 2. <= 3.            larger -> stronger filtering\n"
735 "fq     forceQuant      <quantizer>             force quantizer\n"
736 "Usage:\n"
737 "<filterName>[:<option>[:<option>...]][[,|/][-]<filterName>[:<option>...]]...\n"
738 "long form example:\n"
739 "vdeblock:autoq/hdeblock:autoq/linblenddeint    default,-vdeblock\n"
740 "short form example:\n"
741 "vb:a/hb:a/lb                                   de,-vb\n"
742 "more examples:\n"
743 "tn:64:128:256\n"
744 "\n"
745 ;
746
747 pp_mode *pp_get_mode_by_name_and_quality(const char *name, int quality)
748 {
749     char temp[GET_MODE_BUFFER_SIZE];
750     char *p= temp;
751     static const char filterDelimiters[] = ",/";
752     static const char optionDelimiters[] = ":";
753     struct PPMode *ppMode;
754     char *filterToken;
755
756     ppMode= av_malloc(sizeof(PPMode));
757
758     ppMode->lumMode= 0;
759     ppMode->chromMode= 0;
760     ppMode->maxTmpNoise[0]= 700;
761     ppMode->maxTmpNoise[1]= 1500;
762     ppMode->maxTmpNoise[2]= 3000;
763     ppMode->maxAllowedY= 234;
764     ppMode->minAllowedY= 16;
765     ppMode->baseDcDiff= 256/8;
766     ppMode->flatnessThreshold= 56-16-1;
767     ppMode->maxClippedThreshold= 0.01;
768     ppMode->error=0;
769
770     memset(temp, 0, GET_MODE_BUFFER_SIZE);
771     av_strlcpy(temp, name, GET_MODE_BUFFER_SIZE - 1);
772
773     av_log(NULL, AV_LOG_DEBUG, "pp: %s\n", name);
774
775     for(;;){
776         char *filterName;
777         int q= 1000000; //PP_QUALITY_MAX;
778         int chrom=-1;
779         int luma=-1;
780         char *option;
781         char *options[OPTIONS_ARRAY_SIZE];
782         int i;
783         int filterNameOk=0;
784         int numOfUnknownOptions=0;
785         int enable=1; //does the user want us to enabled or disabled the filter
786
787         filterToken= strtok(p, filterDelimiters);
788         if(filterToken == NULL) break;
789         p+= strlen(filterToken) + 1; // p points to next filterToken
790         filterName= strtok(filterToken, optionDelimiters);
791         av_log(NULL, AV_LOG_DEBUG, "pp: %s::%s\n", filterToken, filterName);
792
793         if(*filterName == '-'){
794             enable=0;
795             filterName++;
796         }
797
798         for(;;){ //for all options
799             option= strtok(NULL, optionDelimiters);
800             if(option == NULL) break;
801
802             av_log(NULL, AV_LOG_DEBUG, "pp: option: %s\n", option);
803             if(!strcmp("autoq", option) || !strcmp("a", option)) q= quality;
804             else if(!strcmp("nochrom", option) || !strcmp("y", option)) chrom=0;
805             else if(!strcmp("chrom", option) || !strcmp("c", option)) chrom=1;
806             else if(!strcmp("noluma", option) || !strcmp("n", option)) luma=0;
807             else{
808                 options[numOfUnknownOptions] = option;
809                 numOfUnknownOptions++;
810             }
811             if(numOfUnknownOptions >= OPTIONS_ARRAY_SIZE-1) break;
812         }
813         options[numOfUnknownOptions] = NULL;
814
815         /* replace stuff from the replace Table */
816         for(i=0; replaceTable[2*i]!=NULL; i++){
817             if(!strcmp(replaceTable[2*i], filterName)){
818                 int newlen= strlen(replaceTable[2*i + 1]);
819                 int plen;
820                 int spaceLeft;
821
822                 p--, *p=',';
823
824                 plen= strlen(p);
825                 spaceLeft= p - temp + plen;
826                 if(spaceLeft + newlen  >= GET_MODE_BUFFER_SIZE - 1){
827                     ppMode->error++;
828                     break;
829                 }
830                 memmove(p + newlen, p, plen+1);
831                 memcpy(p, replaceTable[2*i + 1], newlen);
832                 filterNameOk=1;
833             }
834         }
835
836         for(i=0; filters[i].shortName!=NULL; i++){
837             if(   !strcmp(filters[i].longName, filterName)
838                || !strcmp(filters[i].shortName, filterName)){
839                 ppMode->lumMode &= ~filters[i].mask;
840                 ppMode->chromMode &= ~filters[i].mask;
841
842                 filterNameOk=1;
843                 if(!enable) break; // user wants to disable it
844
845                 if(q >= filters[i].minLumQuality && luma)
846                     ppMode->lumMode|= filters[i].mask;
847                 if(chrom==1 || (chrom==-1 && filters[i].chromDefault))
848                     if(q >= filters[i].minChromQuality)
849                             ppMode->chromMode|= filters[i].mask;
850
851                 if(filters[i].mask == LEVEL_FIX){
852                     int o;
853                     ppMode->minAllowedY= 16;
854                     ppMode->maxAllowedY= 234;
855                     for(o=0; options[o]!=NULL; o++){
856                         if(  !strcmp(options[o],"fullyrange")
857                            ||!strcmp(options[o],"f")){
858                             ppMode->minAllowedY= 0;
859                             ppMode->maxAllowedY= 255;
860                             numOfUnknownOptions--;
861                         }
862                     }
863                 }
864                 else if(filters[i].mask == TEMP_NOISE_FILTER)
865                 {
866                     int o;
867                     int numOfNoises=0;
868
869                     for(o=0; options[o]!=NULL; o++){
870                         char *tail;
871                         ppMode->maxTmpNoise[numOfNoises]=
872                             strtol(options[o], &tail, 0);
873                         if(tail!=options[o]){
874                             numOfNoises++;
875                             numOfUnknownOptions--;
876                             if(numOfNoises >= 3) break;
877                         }
878                     }
879                 }
880                 else if(filters[i].mask == V_DEBLOCK   || filters[i].mask == H_DEBLOCK
881                      || filters[i].mask == V_A_DEBLOCK || filters[i].mask == H_A_DEBLOCK){
882                     int o;
883
884                     for(o=0; options[o]!=NULL && o<2; o++){
885                         char *tail;
886                         int val= strtol(options[o], &tail, 0);
887                         if(tail==options[o]) break;
888
889                         numOfUnknownOptions--;
890                         if(o==0) ppMode->baseDcDiff= val;
891                         else ppMode->flatnessThreshold= val;
892                     }
893                 }
894                 else if(filters[i].mask == FORCE_QUANT){
895                     int o;
896                     ppMode->forcedQuant= 15;
897
898                     for(o=0; options[o]!=NULL && o<1; o++){
899                         char *tail;
900                         int val= strtol(options[o], &tail, 0);
901                         if(tail==options[o]) break;
902
903                         numOfUnknownOptions--;
904                         ppMode->forcedQuant= val;
905                     }
906                 }
907             }
908         }
909         if(!filterNameOk) ppMode->error++;
910         ppMode->error += numOfUnknownOptions;
911     }
912
913     av_log(NULL, AV_LOG_DEBUG, "pp: lumMode=%X, chromMode=%X\n", ppMode->lumMode, ppMode->chromMode);
914     if(ppMode->error){
915         av_log(NULL, AV_LOG_ERROR, "%d errors in postprocess string \"%s\"\n", ppMode->error, name);
916         av_free(ppMode);
917         return NULL;
918     }
919     return ppMode;
920 }
921
922 void pp_free_mode(pp_mode *mode){
923     av_free(mode);
924 }
925
926 static void reallocAlign(void **p, int alignment, int size){
927     av_free(*p);
928     *p= av_mallocz(size);
929 }
930
931 static void reallocBuffers(PPContext *c, int width, int height, int stride, int qpStride){
932     int mbWidth = (width+15)>>4;
933     int mbHeight= (height+15)>>4;
934     int i;
935
936     c->stride= stride;
937     c->qpStride= qpStride;
938
939     reallocAlign((void **)&c->tempDst, 8, stride*24);
940     reallocAlign((void **)&c->tempSrc, 8, stride*24);
941     reallocAlign((void **)&c->tempBlocks, 8, 2*16*8);
942     reallocAlign((void **)&c->yHistogram, 8, 256*sizeof(uint64_t));
943     for(i=0; i<256; i++)
944             c->yHistogram[i]= width*height/64*15/256;
945
946     for(i=0; i<3; i++){
947         //Note: The +17*1024 is just there so i do not have to worry about r/w over the end.
948         reallocAlign((void **)&c->tempBlurred[i], 8, stride*mbHeight*16 + 17*1024);
949         reallocAlign((void **)&c->tempBlurredPast[i], 8, 256*((height+7)&(~7))/2 + 17*1024);//FIXME size
950     }
951
952     reallocAlign((void **)&c->deintTemp, 8, 2*width+32);
953     reallocAlign((void **)&c->nonBQPTable, 8, qpStride*mbHeight*sizeof(QP_STORE_T));
954     reallocAlign((void **)&c->stdQPTable, 8, qpStride*mbHeight*sizeof(QP_STORE_T));
955     reallocAlign((void **)&c->forcedQPTable, 8, mbWidth*sizeof(QP_STORE_T));
956 }
957
958 static const char * context_to_name(void * ptr) {
959     return "postproc";
960 }
961
962 static const AVClass av_codec_context_class = { "Postproc", context_to_name, NULL };
963
964 pp_context *pp_get_context(int width, int height, int cpuCaps){
965     PPContext *c= av_malloc(sizeof(PPContext));
966     int stride= FFALIGN(width, 16);  //assumed / will realloc if needed
967     int qpStride= (width+15)/16 + 2; //assumed / will realloc if needed
968
969     memset(c, 0, sizeof(PPContext));
970     c->av_class = &av_codec_context_class;
971     c->cpuCaps= cpuCaps;
972     if(cpuCaps&PP_FORMAT){
973         c->hChromaSubSample= cpuCaps&0x3;
974         c->vChromaSubSample= (cpuCaps>>4)&0x3;
975     }else{
976         c->hChromaSubSample= 1;
977         c->vChromaSubSample= 1;
978     }
979
980     reallocBuffers(c, width, height, stride, qpStride);
981
982     c->frameNum=-1;
983
984     return c;
985 }
986
987 void pp_free_context(void *vc){
988     PPContext *c = (PPContext*)vc;
989     int i;
990
991     for(i=0; i<3; i++) av_free(c->tempBlurred[i]);
992     for(i=0; i<3; i++) av_free(c->tempBlurredPast[i]);
993
994     av_free(c->tempBlocks);
995     av_free(c->yHistogram);
996     av_free(c->tempDst);
997     av_free(c->tempSrc);
998     av_free(c->deintTemp);
999     av_free(c->stdQPTable);
1000     av_free(c->nonBQPTable);
1001     av_free(c->forcedQPTable);
1002
1003     memset(c, 0, sizeof(PPContext));
1004
1005     av_free(c);
1006 }
1007
1008 void  pp_postprocess(const uint8_t * src[3], const int srcStride[3],
1009                      uint8_t * dst[3], const int dstStride[3],
1010                      int width, int height,
1011                      const QP_STORE_T *QP_store,  int QPStride,
1012                      pp_mode *vm,  void *vc, int pict_type)
1013 {
1014     int mbWidth = (width+15)>>4;
1015     int mbHeight= (height+15)>>4;
1016     PPMode *mode = (PPMode*)vm;
1017     PPContext *c = (PPContext*)vc;
1018     int minStride= FFMAX(FFABS(srcStride[0]), FFABS(dstStride[0]));
1019     int absQPStride = FFABS(QPStride);
1020
1021     // c->stride and c->QPStride are always positive
1022     if(c->stride < minStride || c->qpStride < absQPStride)
1023         reallocBuffers(c, width, height,
1024                        FFMAX(minStride, c->stride),
1025                        FFMAX(c->qpStride, absQPStride));
1026
1027     if(QP_store==NULL || (mode->lumMode & FORCE_QUANT)){
1028         int i;
1029         QP_store= c->forcedQPTable;
1030         absQPStride = QPStride = 0;
1031         if(mode->lumMode & FORCE_QUANT)
1032             for(i=0; i<mbWidth; i++) c->forcedQPTable[i]= mode->forcedQuant;
1033         else
1034             for(i=0; i<mbWidth; i++) c->forcedQPTable[i]= 1;
1035     }
1036
1037     if(pict_type & PP_PICT_TYPE_QP2){
1038         int i;
1039         const int count= mbHeight * absQPStride;
1040         for(i=0; i<(count>>2); i++){
1041             ((uint32_t*)c->stdQPTable)[i] = (((const uint32_t*)QP_store)[i]>>1) & 0x7F7F7F7F;
1042         }
1043         for(i<<=2; i<count; i++){
1044             c->stdQPTable[i] = QP_store[i]>>1;
1045         }
1046         QP_store= c->stdQPTable;
1047         QPStride= absQPStride;
1048     }
1049
1050     if(0){
1051         int x,y;
1052         for(y=0; y<mbHeight; y++){
1053             for(x=0; x<mbWidth; x++){
1054                 av_log(c, AV_LOG_INFO, "%2d ", QP_store[x + y*QPStride]);
1055             }
1056             av_log(c, AV_LOG_INFO, "\n");
1057         }
1058         av_log(c, AV_LOG_INFO, "\n");
1059     }
1060
1061     if((pict_type&7)!=3){
1062         if (QPStride >= 0){
1063             int i;
1064             const int count= mbHeight * QPStride;
1065             for(i=0; i<(count>>2); i++){
1066                 ((uint32_t*)c->nonBQPTable)[i] = ((const uint32_t*)QP_store)[i] & 0x3F3F3F3F;
1067             }
1068             for(i<<=2; i<count; i++){
1069                 c->nonBQPTable[i] = QP_store[i] & 0x3F;
1070             }
1071         } else {
1072             int i,j;
1073             for(i=0; i<mbHeight; i++) {
1074                 for(j=0; j<absQPStride; j++) {
1075                     c->nonBQPTable[i*absQPStride+j] = QP_store[i*QPStride+j] & 0x3F;
1076                 }
1077             }
1078         }
1079     }
1080
1081     av_log(c, AV_LOG_DEBUG, "using npp filters 0x%X/0x%X\n",
1082            mode->lumMode, mode->chromMode);
1083
1084     postProcess(src[0], srcStride[0], dst[0], dstStride[0],
1085                 width, height, QP_store, QPStride, 0, mode, c);
1086
1087     width  = (width )>>c->hChromaSubSample;
1088     height = (height)>>c->vChromaSubSample;
1089
1090     if(mode->chromMode){
1091         postProcess(src[1], srcStride[1], dst[1], dstStride[1],
1092                     width, height, QP_store, QPStride, 1, mode, c);
1093         postProcess(src[2], srcStride[2], dst[2], dstStride[2],
1094                     width, height, QP_store, QPStride, 2, mode, c);
1095     }
1096     else if(srcStride[1] == dstStride[1] && srcStride[2] == dstStride[2]){
1097         linecpy(dst[1], src[1], height, srcStride[1]);
1098         linecpy(dst[2], src[2], height, srcStride[2]);
1099     }else{
1100         int y;
1101         for(y=0; y<height; y++){
1102             memcpy(&(dst[1][y*dstStride[1]]), &(src[1][y*srcStride[1]]), width);
1103             memcpy(&(dst[2][y*dstStride[2]]), &(src[2][y*srcStride[2]]), width);
1104         }
1105     }
1106 }