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