]> git.sesse.net Git - ffmpeg/blob - libpostproc/postprocess.c
avutil: Add missing test programs to Makefile.
[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 Libav.
7  *
8  * Libav 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  * Libav 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 Libav; 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 LIBAV_CONFIGURATION;
99 }
100
101 const char *postproc_license(void)
102 {
103 #define LICENSE_PREFIX "libpostproc license: "
104     return LICENSE_PREFIX LIBAV_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     for(i=0; i<2; i++){
250         if((unsigned)(src[0] - src[5] + 2*QP) > 4*QP) return 0;
251         src += stride;
252         if((unsigned)(src[2] - src[7] + 2*QP) > 4*QP) return 0;
253         src += stride;
254         if((unsigned)(src[4] - src[1] + 2*QP) > 4*QP) return 0;
255         src += stride;
256         if((unsigned)(src[6] - src[3] + 2*QP) > 4*QP) return 0;
257         src += stride;
258     }
259     return 1;
260 }
261
262 static inline int isVertMinMaxOk_C(uint8_t src[], int stride, int QP)
263 {
264     int x;
265     src+= stride*4;
266     for(x=0; x<BLOCK_SIZE; x+=4){
267         if((unsigned)(src[  x + 0*stride] - src[  x + 5*stride] + 2*QP) > 4*QP) return 0;
268         if((unsigned)(src[1+x + 2*stride] - src[1+x + 7*stride] + 2*QP) > 4*QP) return 0;
269         if((unsigned)(src[2+x + 4*stride] - src[2+x + 1*stride] + 2*QP) > 4*QP) return 0;
270         if((unsigned)(src[3+x + 6*stride] - src[3+x + 3*stride] + 2*QP) > 4*QP) return 0;
271     }
272     return 1;
273 }
274
275 static inline int horizClassify_C(uint8_t src[], int stride, PPContext *c)
276 {
277     if( isHorizDC_C(src, stride, c) ){
278         if( isHorizMinMaxOk_C(src, stride, c->QP) )
279             return 1;
280         else
281             return 0;
282     }else{
283         return 2;
284     }
285 }
286
287 static inline int vertClassify_C(uint8_t src[], int stride, PPContext *c)
288 {
289     if( isVertDC_C(src, stride, c) ){
290         if( isVertMinMaxOk_C(src, stride, c->QP) )
291             return 1;
292         else
293             return 0;
294     }else{
295         return 2;
296     }
297 }
298
299 static inline void doHorizDefFilter_C(uint8_t dst[], int stride, PPContext *c)
300 {
301     int y;
302     for(y=0; y<BLOCK_SIZE; y++){
303         const int middleEnergy= 5*(dst[4] - dst[3]) + 2*(dst[2] - dst[5]);
304
305         if(FFABS(middleEnergy) < 8*c->QP){
306             const int q=(dst[3] - dst[4])/2;
307             const int leftEnergy=  5*(dst[2] - dst[1]) + 2*(dst[0] - dst[3]);
308             const int rightEnergy= 5*(dst[6] - dst[5]) + 2*(dst[4] - dst[7]);
309
310             int d= FFABS(middleEnergy) - FFMIN( FFABS(leftEnergy), FFABS(rightEnergy) );
311             d= FFMAX(d, 0);
312
313             d= (5*d + 32) >> 6;
314             d*= FFSIGN(-middleEnergy);
315
316             if(q>0)
317             {
318                 d= d<0 ? 0 : d;
319                 d= d>q ? q : d;
320             }
321             else
322             {
323                 d= d>0 ? 0 : d;
324                 d= d<q ? q : d;
325             }
326
327             dst[3]-= d;
328             dst[4]+= d;
329         }
330         dst+= stride;
331     }
332 }
333
334 /**
335  * Do a horizontal low pass filter on the 10x8 block (dst points to middle 8x8 Block)
336  * using the 9-Tap Filter (1,1,2,2,4,2,2,1,1)/16 (C version)
337  */
338 static inline void doHorizLowPass_C(uint8_t dst[], int stride, PPContext *c)
339 {
340     int y;
341     for(y=0; y<BLOCK_SIZE; y++){
342         const int first= FFABS(dst[-1] - dst[0]) < c->QP ? dst[-1] : dst[0];
343         const int last= FFABS(dst[8] - dst[7]) < c->QP ? dst[8] : dst[7];
344
345         int sums[10];
346         sums[0] = 4*first + dst[0] + dst[1] + dst[2] + 4;
347         sums[1] = sums[0] - first  + dst[3];
348         sums[2] = sums[1] - first  + dst[4];
349         sums[3] = sums[2] - first  + dst[5];
350         sums[4] = sums[3] - first  + dst[6];
351         sums[5] = sums[4] - dst[0] + dst[7];
352         sums[6] = sums[5] - dst[1] + last;
353         sums[7] = sums[6] - dst[2] + last;
354         sums[8] = sums[7] - dst[3] + last;
355         sums[9] = sums[8] - dst[4] + last;
356
357         dst[0]= (sums[0] + sums[2] + 2*dst[0])>>4;
358         dst[1]= (sums[1] + sums[3] + 2*dst[1])>>4;
359         dst[2]= (sums[2] + sums[4] + 2*dst[2])>>4;
360         dst[3]= (sums[3] + sums[5] + 2*dst[3])>>4;
361         dst[4]= (sums[4] + sums[6] + 2*dst[4])>>4;
362         dst[5]= (sums[5] + sums[7] + 2*dst[5])>>4;
363         dst[6]= (sums[6] + sums[8] + 2*dst[6])>>4;
364         dst[7]= (sums[7] + sums[9] + 2*dst[7])>>4;
365
366         dst+= stride;
367     }
368 }
369
370 /**
371  * Experimental Filter 1 (Horizontal)
372  * will not damage linear gradients
373  * Flat blocks should look like they were passed through the (1,1,2,2,4,2,2,1,1) 9-Tap filter
374  * can only smooth blocks at the expected locations (it cannot smooth them if they did move)
375  * MMX2 version does correct clipping C version does not
376  * not identical with the vertical one
377  */
378 static inline void horizX1Filter(uint8_t *src, int stride, int QP)
379 {
380     int y;
381     static uint64_t *lut= NULL;
382     if(lut==NULL)
383     {
384         int i;
385         lut = av_malloc(256*8);
386         for(i=0; i<256; i++)
387         {
388             int v= i < 128 ? 2*i : 2*(i-256);
389 /*
390 //Simulate 112242211 9-Tap filter
391             uint64_t a= (v/16)  & 0xFF;
392             uint64_t b= (v/8)   & 0xFF;
393             uint64_t c= (v/4)   & 0xFF;
394             uint64_t d= (3*v/8) & 0xFF;
395 */
396 //Simulate piecewise linear interpolation
397             uint64_t a= (v/16)   & 0xFF;
398             uint64_t b= (v*3/16) & 0xFF;
399             uint64_t c= (v*5/16) & 0xFF;
400             uint64_t d= (7*v/16) & 0xFF;
401             uint64_t A= (0x100 - a)&0xFF;
402             uint64_t B= (0x100 - b)&0xFF;
403             uint64_t C= (0x100 - c)&0xFF;
404             uint64_t D= (0x100 - c)&0xFF;
405
406             lut[i]   = (a<<56) | (b<<48) | (c<<40) | (d<<32) |
407                        (D<<24) | (C<<16) | (B<<8)  | (A);
408             //lut[i] = (v<<32) | (v<<24);
409         }
410     }
411
412     for(y=0; y<BLOCK_SIZE; y++){
413         int a= src[1] - src[2];
414         int b= src[3] - src[4];
415         int c= src[5] - src[6];
416
417         int d= FFMAX(FFABS(b) - (FFABS(a) + FFABS(c))/2, 0);
418
419         if(d < QP){
420             int v = d * FFSIGN(-b);
421
422             src[1] +=v/8;
423             src[2] +=v/4;
424             src[3] +=3*v/8;
425             src[4] -=3*v/8;
426             src[5] -=v/4;
427             src[6] -=v/8;
428         }
429         src+=stride;
430     }
431 }
432
433 /**
434  * accurate deblock filter
435  */
436 static av_always_inline void do_a_deblock_C(uint8_t *src, int step, int stride, PPContext *c){
437     int y;
438     const int QP= c->QP;
439     const int dcOffset= ((c->nonBQP*c->ppMode.baseDcDiff)>>8) + 1;
440     const int dcThreshold= dcOffset*2 + 1;
441 //START_TIMER
442     src+= step*4; // src points to begin of the 8x8 Block
443     for(y=0; y<8; y++){
444         int numEq= 0;
445
446         if(((unsigned)(src[-1*step] - src[0*step] + dcOffset)) < dcThreshold) numEq++;
447         if(((unsigned)(src[ 0*step] - src[1*step] + dcOffset)) < dcThreshold) numEq++;
448         if(((unsigned)(src[ 1*step] - src[2*step] + dcOffset)) < dcThreshold) numEq++;
449         if(((unsigned)(src[ 2*step] - src[3*step] + dcOffset)) < dcThreshold) numEq++;
450         if(((unsigned)(src[ 3*step] - src[4*step] + dcOffset)) < dcThreshold) numEq++;
451         if(((unsigned)(src[ 4*step] - src[5*step] + dcOffset)) < dcThreshold) numEq++;
452         if(((unsigned)(src[ 5*step] - src[6*step] + dcOffset)) < dcThreshold) numEq++;
453         if(((unsigned)(src[ 6*step] - src[7*step] + dcOffset)) < dcThreshold) numEq++;
454         if(((unsigned)(src[ 7*step] - src[8*step] + dcOffset)) < dcThreshold) numEq++;
455         if(numEq > c->ppMode.flatnessThreshold){
456             int min, max, x;
457
458             if(src[0] > src[step]){
459                 max= src[0];
460                 min= src[step];
461             }else{
462                 max= src[step];
463                 min= src[0];
464             }
465             for(x=2; x<8; x+=2){
466                 if(src[x*step] > src[(x+1)*step]){
467                         if(src[x    *step] > max) max= src[ x   *step];
468                         if(src[(x+1)*step] < min) min= src[(x+1)*step];
469                 }else{
470                         if(src[(x+1)*step] > max) max= src[(x+1)*step];
471                         if(src[ x   *step] < min) min= src[ x   *step];
472                 }
473             }
474             if(max-min < 2*QP){
475                 const int first= FFABS(src[-1*step] - src[0]) < QP ? src[-1*step] : src[0];
476                 const int last= FFABS(src[8*step] - src[7*step]) < QP ? src[8*step] : src[7*step];
477
478                 int sums[10];
479                 sums[0] = 4*first + src[0*step] + src[1*step] + src[2*step] + 4;
480                 sums[1] = sums[0] - first       + src[3*step];
481                 sums[2] = sums[1] - first       + src[4*step];
482                 sums[3] = sums[2] - first       + src[5*step];
483                 sums[4] = sums[3] - first       + src[6*step];
484                 sums[5] = sums[4] - src[0*step] + src[7*step];
485                 sums[6] = sums[5] - src[1*step] + last;
486                 sums[7] = sums[6] - src[2*step] + last;
487                 sums[8] = sums[7] - src[3*step] + last;
488                 sums[9] = sums[8] - src[4*step] + last;
489
490                 src[0*step]= (sums[0] + sums[2] + 2*src[0*step])>>4;
491                 src[1*step]= (sums[1] + sums[3] + 2*src[1*step])>>4;
492                 src[2*step]= (sums[2] + sums[4] + 2*src[2*step])>>4;
493                 src[3*step]= (sums[3] + sums[5] + 2*src[3*step])>>4;
494                 src[4*step]= (sums[4] + sums[6] + 2*src[4*step])>>4;
495                 src[5*step]= (sums[5] + sums[7] + 2*src[5*step])>>4;
496                 src[6*step]= (sums[6] + sums[8] + 2*src[6*step])>>4;
497                 src[7*step]= (sums[7] + sums[9] + 2*src[7*step])>>4;
498             }
499         }else{
500             const int middleEnergy= 5*(src[4*step] - src[3*step]) + 2*(src[2*step] - src[5*step]);
501
502             if(FFABS(middleEnergy) < 8*QP){
503                 const int q=(src[3*step] - src[4*step])/2;
504                 const int leftEnergy=  5*(src[2*step] - src[1*step]) + 2*(src[0*step] - src[3*step]);
505                 const int rightEnergy= 5*(src[6*step] - src[5*step]) + 2*(src[4*step] - src[7*step]);
506
507                 int d= FFABS(middleEnergy) - FFMIN( FFABS(leftEnergy), FFABS(rightEnergy) );
508                 d= FFMAX(d, 0);
509
510                 d= (5*d + 32) >> 6;
511                 d*= FFSIGN(-middleEnergy);
512
513                 if(q>0){
514                     d= d<0 ? 0 : d;
515                     d= d>q ? q : d;
516                 }else{
517                     d= d>0 ? 0 : d;
518                     d= d<q ? q : d;
519                 }
520
521                 src[3*step]-= d;
522                 src[4*step]+= d;
523             }
524         }
525
526         src += stride;
527     }
528 /*if(step==16){
529     STOP_TIMER("step16")
530 }else{
531     STOP_TIMER("stepX")
532 }*/
533 }
534
535 //Note: we have C, MMX, MMX2, 3DNOW version there is no 3DNOW+MMX2 one
536 //Plain C versions
537 #if !(HAVE_MMX || HAVE_ALTIVEC) || CONFIG_RUNTIME_CPUDETECT
538 #define COMPILE_C
539 #endif
540
541 #if HAVE_ALTIVEC
542 #define COMPILE_ALTIVEC
543 #endif //HAVE_ALTIVEC
544
545 #if ARCH_X86
546
547 #if (HAVE_MMX && !HAVE_AMD3DNOW && !HAVE_MMX2) || CONFIG_RUNTIME_CPUDETECT
548 #define COMPILE_MMX
549 #endif
550
551 #if HAVE_MMX2 || CONFIG_RUNTIME_CPUDETECT
552 #define COMPILE_MMX2
553 #endif
554
555 #if (HAVE_AMD3DNOW && !HAVE_MMX2) || CONFIG_RUNTIME_CPUDETECT
556 #define COMPILE_3DNOW
557 #endif
558 #endif /* ARCH_X86 */
559
560 #undef HAVE_MMX
561 #define HAVE_MMX 0
562 #undef HAVE_MMX2
563 #define HAVE_MMX2 0
564 #undef HAVE_AMD3DNOW
565 #define HAVE_AMD3DNOW 0
566 #undef HAVE_ALTIVEC
567 #define HAVE_ALTIVEC 0
568
569 #ifdef COMPILE_C
570 #define RENAME(a) a ## _C
571 #include "postprocess_template.c"
572 #endif
573
574 #ifdef COMPILE_ALTIVEC
575 #undef RENAME
576 #undef HAVE_ALTIVEC
577 #define HAVE_ALTIVEC 1
578 #define RENAME(a) a ## _altivec
579 #include "postprocess_altivec_template.c"
580 #include "postprocess_template.c"
581 #endif
582
583 //MMX versions
584 #ifdef COMPILE_MMX
585 #undef RENAME
586 #undef HAVE_MMX
587 #define HAVE_MMX 1
588 #define RENAME(a) a ## _MMX
589 #include "postprocess_template.c"
590 #endif
591
592 //MMX2 versions
593 #ifdef COMPILE_MMX2
594 #undef RENAME
595 #undef HAVE_MMX
596 #undef HAVE_MMX2
597 #define HAVE_MMX 1
598 #define HAVE_MMX2 1
599 #define RENAME(a) a ## _MMX2
600 #include "postprocess_template.c"
601 #endif
602
603 //3DNOW versions
604 #ifdef COMPILE_3DNOW
605 #undef RENAME
606 #undef HAVE_MMX
607 #undef HAVE_MMX2
608 #undef HAVE_AMD3DNOW
609 #define HAVE_MMX 1
610 #define HAVE_MMX2 0
611 #define HAVE_AMD3DNOW 1
612 #define RENAME(a) a ## _3DNow
613 #include "postprocess_template.c"
614 #endif
615
616 // minor note: the HAVE_xyz is messed up after that line so do not use it.
617
618 static inline void postProcess(const uint8_t src[], int srcStride, uint8_t dst[], int dstStride, int width, int height,
619         const QP_STORE_T QPs[], int QPStride, int isColor, pp_mode *vm, pp_context *vc)
620 {
621     PPContext *c= (PPContext *)vc;
622     PPMode *ppMode= (PPMode *)vm;
623     c->ppMode= *ppMode; //FIXME
624
625     // Using ifs here as they are faster than function pointers although the
626     // difference would not be measurable here but it is much better because
627     // someone might exchange the CPU whithout restarting MPlayer ;)
628 #if CONFIG_RUNTIME_CPUDETECT
629 #if ARCH_X86
630     // ordered per speed fastest first
631     if(c->cpuCaps & PP_CPU_CAPS_MMX2)
632         postProcess_MMX2(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
633     else if(c->cpuCaps & PP_CPU_CAPS_3DNOW)
634         postProcess_3DNow(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
635     else if(c->cpuCaps & PP_CPU_CAPS_MMX)
636         postProcess_MMX(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
637     else
638         postProcess_C(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
639 #else
640 #if HAVE_ALTIVEC
641     if(c->cpuCaps & PP_CPU_CAPS_ALTIVEC)
642             postProcess_altivec(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
643     else
644 #endif
645             postProcess_C(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
646 #endif
647 #else //CONFIG_RUNTIME_CPUDETECT
648 #if   HAVE_MMX2
649             postProcess_MMX2(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
650 #elif HAVE_AMD3DNOW
651             postProcess_3DNow(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
652 #elif HAVE_MMX
653             postProcess_MMX(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
654 #elif HAVE_ALTIVEC
655             postProcess_altivec(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
656 #else
657             postProcess_C(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
658 #endif
659 #endif //!CONFIG_RUNTIME_CPUDETECT
660 }
661
662 //static void postProcess(uint8_t src[], int srcStride, uint8_t dst[], int dstStride, int width, int height,
663 //        QP_STORE_T QPs[], int QPStride, int isColor, struct PPMode *ppMode);
664
665 /* -pp Command line Help
666 */
667 const char pp_help[] =
668 "Available postprocessing filters:\n"
669 "Filters                        Options\n"
670 "short  long name       short   long option     Description\n"
671 "*      *               a       autoq           CPU power dependent enabler\n"
672 "                       c       chrom           chrominance filtering enabled\n"
673 "                       y       nochrom         chrominance filtering disabled\n"
674 "                       n       noluma          luma filtering disabled\n"
675 "hb     hdeblock        (2 threshold)           horizontal deblocking filter\n"
676 "       1. difference factor: default=32, higher -> more deblocking\n"
677 "       2. flatness threshold: default=39, lower -> more deblocking\n"
678 "                       the h & v deblocking filters share these\n"
679 "                       so you can't set different thresholds for h / v\n"
680 "vb     vdeblock        (2 threshold)           vertical deblocking filter\n"
681 "ha     hadeblock       (2 threshold)           horizontal deblocking filter\n"
682 "va     vadeblock       (2 threshold)           vertical deblocking filter\n"
683 "h1     x1hdeblock                              experimental h deblock filter 1\n"
684 "v1     x1vdeblock                              experimental v deblock filter 1\n"
685 "dr     dering                                  deringing filter\n"
686 "al     autolevels                              automatic brightness / contrast\n"
687 "                       f        fullyrange     stretch luminance to (0..255)\n"
688 "lb     linblenddeint                           linear blend deinterlacer\n"
689 "li     linipoldeint                            linear interpolating deinterlace\n"
690 "ci     cubicipoldeint                          cubic interpolating deinterlacer\n"
691 "md     mediandeint                             median deinterlacer\n"
692 "fd     ffmpegdeint                             ffmpeg deinterlacer\n"
693 "l5     lowpass5                                FIR lowpass deinterlacer\n"
694 "de     default                                 hb:a,vb:a,dr:a\n"
695 "fa     fast                                    h1:a,v1:a,dr:a\n"
696 "ac                                             ha:a:128:7,va:a,dr:a\n"
697 "tn     tmpnoise        (3 threshold)           temporal noise reducer\n"
698 "                     1. <= 2. <= 3.            larger -> stronger filtering\n"
699 "fq     forceQuant      <quantizer>             force quantizer\n"
700 "Usage:\n"
701 "<filterName>[:<option>[:<option>...]][[,|/][-]<filterName>[:<option>...]]...\n"
702 "long form example:\n"
703 "vdeblock:autoq/hdeblock:autoq/linblenddeint    default,-vdeblock\n"
704 "short form example:\n"
705 "vb:a/hb:a/lb                                   de,-vb\n"
706 "more examples:\n"
707 "tn:64:128:256\n"
708 "\n"
709 ;
710
711 pp_mode *pp_get_mode_by_name_and_quality(const char *name, int quality)
712 {
713     char temp[GET_MODE_BUFFER_SIZE];
714     char *p= temp;
715     static const char filterDelimiters[] = ",/";
716     static const char optionDelimiters[] = ":";
717     struct PPMode *ppMode;
718     char *filterToken;
719
720     ppMode= av_malloc(sizeof(PPMode));
721
722     ppMode->lumMode= 0;
723     ppMode->chromMode= 0;
724     ppMode->maxTmpNoise[0]= 700;
725     ppMode->maxTmpNoise[1]= 1500;
726     ppMode->maxTmpNoise[2]= 3000;
727     ppMode->maxAllowedY= 234;
728     ppMode->minAllowedY= 16;
729     ppMode->baseDcDiff= 256/8;
730     ppMode->flatnessThreshold= 56-16-1;
731     ppMode->maxClippedThreshold= 0.01;
732     ppMode->error=0;
733
734     av_strlcpy(temp, name, GET_MODE_BUFFER_SIZE);
735
736     av_log(NULL, AV_LOG_DEBUG, "pp: %s\n", name);
737
738     for(;;){
739         char *filterName;
740         int q= 1000000; //PP_QUALITY_MAX;
741         int chrom=-1;
742         int luma=-1;
743         char *option;
744         char *options[OPTIONS_ARRAY_SIZE];
745         int i;
746         int filterNameOk=0;
747         int numOfUnknownOptions=0;
748         int enable=1; //does the user want us to enabled or disabled the filter
749
750         filterToken= strtok(p, filterDelimiters);
751         if(filterToken == NULL) break;
752         p+= strlen(filterToken) + 1; // p points to next filterToken
753         filterName= strtok(filterToken, optionDelimiters);
754         av_log(NULL, AV_LOG_DEBUG, "pp: %s::%s\n", filterToken, filterName);
755
756         if(*filterName == '-'){
757             enable=0;
758             filterName++;
759         }
760
761         for(;;){ //for all options
762             option= strtok(NULL, optionDelimiters);
763             if(option == NULL) break;
764
765             av_log(NULL, AV_LOG_DEBUG, "pp: option: %s\n", option);
766             if(!strcmp("autoq", option) || !strcmp("a", option)) q= quality;
767             else if(!strcmp("nochrom", option) || !strcmp("y", option)) chrom=0;
768             else if(!strcmp("chrom", option) || !strcmp("c", option)) chrom=1;
769             else if(!strcmp("noluma", option) || !strcmp("n", option)) luma=0;
770             else{
771                 options[numOfUnknownOptions] = option;
772                 numOfUnknownOptions++;
773             }
774             if(numOfUnknownOptions >= OPTIONS_ARRAY_SIZE-1) break;
775         }
776         options[numOfUnknownOptions] = NULL;
777
778         /* replace stuff from the replace Table */
779         for(i=0; replaceTable[2*i]!=NULL; i++){
780             if(!strcmp(replaceTable[2*i], filterName)){
781                 int newlen= strlen(replaceTable[2*i + 1]);
782                 int plen;
783                 int spaceLeft;
784
785                 if(p==NULL) p= temp, *p=0;      //last filter
786                 else p--, *p=',';               //not last filter
787
788                 plen= strlen(p);
789                 spaceLeft= p - temp + plen;
790                 if(spaceLeft + newlen  >= GET_MODE_BUFFER_SIZE){
791                     ppMode->error++;
792                     break;
793                 }
794                 memmove(p + newlen, p, plen+1);
795                 memcpy(p, replaceTable[2*i + 1], newlen);
796                 filterNameOk=1;
797             }
798         }
799
800         for(i=0; filters[i].shortName!=NULL; i++){
801             if(   !strcmp(filters[i].longName, filterName)
802                || !strcmp(filters[i].shortName, filterName)){
803                 ppMode->lumMode &= ~filters[i].mask;
804                 ppMode->chromMode &= ~filters[i].mask;
805
806                 filterNameOk=1;
807                 if(!enable) break; // user wants to disable it
808
809                 if(q >= filters[i].minLumQuality && luma)
810                     ppMode->lumMode|= filters[i].mask;
811                 if(chrom==1 || (chrom==-1 && filters[i].chromDefault))
812                     if(q >= filters[i].minChromQuality)
813                             ppMode->chromMode|= filters[i].mask;
814
815                 if(filters[i].mask == LEVEL_FIX){
816                     int o;
817                     ppMode->minAllowedY= 16;
818                     ppMode->maxAllowedY= 234;
819                     for(o=0; options[o]!=NULL; o++){
820                         if(  !strcmp(options[o],"fullyrange")
821                            ||!strcmp(options[o],"f")){
822                             ppMode->minAllowedY= 0;
823                             ppMode->maxAllowedY= 255;
824                             numOfUnknownOptions--;
825                         }
826                     }
827                 }
828                 else if(filters[i].mask == TEMP_NOISE_FILTER)
829                 {
830                     int o;
831                     int numOfNoises=0;
832
833                     for(o=0; options[o]!=NULL; o++){
834                         char *tail;
835                         ppMode->maxTmpNoise[numOfNoises]=
836                             strtol(options[o], &tail, 0);
837                         if(tail!=options[o]){
838                             numOfNoises++;
839                             numOfUnknownOptions--;
840                             if(numOfNoises >= 3) break;
841                         }
842                     }
843                 }
844                 else if(filters[i].mask == V_DEBLOCK   || filters[i].mask == H_DEBLOCK
845                      || filters[i].mask == V_A_DEBLOCK || filters[i].mask == H_A_DEBLOCK){
846                     int o;
847
848                     for(o=0; options[o]!=NULL && o<2; o++){
849                         char *tail;
850                         int val= strtol(options[o], &tail, 0);
851                         if(tail==options[o]) break;
852
853                         numOfUnknownOptions--;
854                         if(o==0) ppMode->baseDcDiff= val;
855                         else ppMode->flatnessThreshold= val;
856                     }
857                 }
858                 else if(filters[i].mask == FORCE_QUANT){
859                     int o;
860                     ppMode->forcedQuant= 15;
861
862                     for(o=0; options[o]!=NULL && o<1; o++){
863                         char *tail;
864                         int val= strtol(options[o], &tail, 0);
865                         if(tail==options[o]) break;
866
867                         numOfUnknownOptions--;
868                         ppMode->forcedQuant= val;
869                     }
870                 }
871             }
872         }
873         if(!filterNameOk) ppMode->error++;
874         ppMode->error += numOfUnknownOptions;
875     }
876
877     av_log(NULL, AV_LOG_DEBUG, "pp: lumMode=%X, chromMode=%X\n", ppMode->lumMode, ppMode->chromMode);
878     if(ppMode->error){
879         av_log(NULL, AV_LOG_ERROR, "%d errors in postprocess string \"%s\"\n", ppMode->error, name);
880         av_free(ppMode);
881         return NULL;
882     }
883     return ppMode;
884 }
885
886 void pp_free_mode(pp_mode *mode){
887     av_free(mode);
888 }
889
890 static void reallocAlign(void **p, int alignment, int size){
891     av_free(*p);
892     *p= av_mallocz(size);
893 }
894
895 static void reallocBuffers(PPContext *c, int width, int height, int stride, int qpStride){
896     int mbWidth = (width+15)>>4;
897     int mbHeight= (height+15)>>4;
898     int i;
899
900     c->stride= stride;
901     c->qpStride= qpStride;
902
903     reallocAlign((void **)&c->tempDst, 8, stride*24);
904     reallocAlign((void **)&c->tempSrc, 8, stride*24);
905     reallocAlign((void **)&c->tempBlocks, 8, 2*16*8);
906     reallocAlign((void **)&c->yHistogram, 8, 256*sizeof(uint64_t));
907     for(i=0; i<256; i++)
908             c->yHistogram[i]= width*height/64*15/256;
909
910     for(i=0; i<3; i++){
911         //Note: The +17*1024 is just there so i do not have to worry about r/w over the end.
912         reallocAlign((void **)&c->tempBlurred[i], 8, stride*mbHeight*16 + 17*1024);
913         reallocAlign((void **)&c->tempBlurredPast[i], 8, 256*((height+7)&(~7))/2 + 17*1024);//FIXME size
914     }
915
916     reallocAlign((void **)&c->deintTemp, 8, 2*width+32);
917     reallocAlign((void **)&c->nonBQPTable, 8, qpStride*mbHeight*sizeof(QP_STORE_T));
918     reallocAlign((void **)&c->stdQPTable, 8, qpStride*mbHeight*sizeof(QP_STORE_T));
919     reallocAlign((void **)&c->forcedQPTable, 8, mbWidth*sizeof(QP_STORE_T));
920 }
921
922 static const char * context_to_name(void * ptr) {
923     return "postproc";
924 }
925
926 static const AVClass av_codec_context_class = { "Postproc", context_to_name, NULL };
927
928 pp_context *pp_get_context(int width, int height, int cpuCaps){
929     PPContext *c= av_malloc(sizeof(PPContext));
930     int stride= FFALIGN(width, 16);  //assumed / will realloc if needed
931     int qpStride= (width+15)/16 + 2; //assumed / will realloc if needed
932
933     memset(c, 0, sizeof(PPContext));
934     c->av_class = &av_codec_context_class;
935     c->cpuCaps= cpuCaps;
936     if(cpuCaps&PP_FORMAT){
937         c->hChromaSubSample= cpuCaps&0x3;
938         c->vChromaSubSample= (cpuCaps>>4)&0x3;
939     }else{
940         c->hChromaSubSample= 1;
941         c->vChromaSubSample= 1;
942     }
943
944     reallocBuffers(c, width, height, stride, qpStride);
945
946     c->frameNum=-1;
947
948     return c;
949 }
950
951 void pp_free_context(void *vc){
952     PPContext *c = (PPContext*)vc;
953     int i;
954
955     for(i=0; i<3; i++) av_free(c->tempBlurred[i]);
956     for(i=0; i<3; i++) av_free(c->tempBlurredPast[i]);
957
958     av_free(c->tempBlocks);
959     av_free(c->yHistogram);
960     av_free(c->tempDst);
961     av_free(c->tempSrc);
962     av_free(c->deintTemp);
963     av_free(c->stdQPTable);
964     av_free(c->nonBQPTable);
965     av_free(c->forcedQPTable);
966
967     memset(c, 0, sizeof(PPContext));
968
969     av_free(c);
970 }
971
972 void  pp_postprocess(const uint8_t * src[3], const int srcStride[3],
973                      uint8_t * dst[3], const int dstStride[3],
974                      int width, int height,
975                      const QP_STORE_T *QP_store,  int QPStride,
976                      pp_mode *vm,  void *vc, int pict_type)
977 {
978     int mbWidth = (width+15)>>4;
979     int mbHeight= (height+15)>>4;
980     PPMode *mode = (PPMode*)vm;
981     PPContext *c = (PPContext*)vc;
982     int minStride= FFMAX(FFABS(srcStride[0]), FFABS(dstStride[0]));
983     int absQPStride = FFABS(QPStride);
984
985     // c->stride and c->QPStride are always positive
986     if(c->stride < minStride || c->qpStride < absQPStride)
987         reallocBuffers(c, width, height,
988                        FFMAX(minStride, c->stride),
989                        FFMAX(c->qpStride, absQPStride));
990
991     if(QP_store==NULL || (mode->lumMode & FORCE_QUANT)){
992         int i;
993         QP_store= c->forcedQPTable;
994         absQPStride = QPStride = 0;
995         if(mode->lumMode & FORCE_QUANT)
996             for(i=0; i<mbWidth; i++) c->forcedQPTable[i]= mode->forcedQuant;
997         else
998             for(i=0; i<mbWidth; i++) c->forcedQPTable[i]= 1;
999     }
1000
1001     if(pict_type & PP_PICT_TYPE_QP2){
1002         int i;
1003         const int count= mbHeight * absQPStride;
1004         for(i=0; i<(count>>2); i++){
1005             ((uint32_t*)c->stdQPTable)[i] = (((const uint32_t*)QP_store)[i]>>1) & 0x7F7F7F7F;
1006         }
1007         for(i<<=2; i<count; i++){
1008             c->stdQPTable[i] = QP_store[i]>>1;
1009         }
1010         QP_store= c->stdQPTable;
1011         QPStride= absQPStride;
1012     }
1013
1014     if(0){
1015         int x,y;
1016         for(y=0; y<mbHeight; y++){
1017             for(x=0; x<mbWidth; x++){
1018                 av_log(c, AV_LOG_INFO, "%2d ", QP_store[x + y*QPStride]);
1019             }
1020             av_log(c, AV_LOG_INFO, "\n");
1021         }
1022         av_log(c, AV_LOG_INFO, "\n");
1023     }
1024
1025     if((pict_type&7)!=3){
1026         if (QPStride >= 0){
1027             int i;
1028             const int count= mbHeight * QPStride;
1029             for(i=0; i<(count>>2); i++){
1030                 ((uint32_t*)c->nonBQPTable)[i] = ((const uint32_t*)QP_store)[i] & 0x3F3F3F3F;
1031             }
1032             for(i<<=2; i<count; i++){
1033                 c->nonBQPTable[i] = QP_store[i] & 0x3F;
1034             }
1035         } else {
1036             int i,j;
1037             for(i=0; i<mbHeight; i++) {
1038                 for(j=0; j<absQPStride; j++) {
1039                     c->nonBQPTable[i*absQPStride+j] = QP_store[i*QPStride+j] & 0x3F;
1040                 }
1041             }
1042         }
1043     }
1044
1045     av_log(c, AV_LOG_DEBUG, "using npp filters 0x%X/0x%X\n",
1046            mode->lumMode, mode->chromMode);
1047
1048     postProcess(src[0], srcStride[0], dst[0], dstStride[0],
1049                 width, height, QP_store, QPStride, 0, mode, c);
1050
1051     width  = (width )>>c->hChromaSubSample;
1052     height = (height)>>c->vChromaSubSample;
1053
1054     if(mode->chromMode){
1055         postProcess(src[1], srcStride[1], dst[1], dstStride[1],
1056                     width, height, QP_store, QPStride, 1, mode, c);
1057         postProcess(src[2], srcStride[2], dst[2], dstStride[2],
1058                     width, height, QP_store, QPStride, 2, mode, c);
1059     }
1060     else if(srcStride[1] == dstStride[1] && srcStride[2] == dstStride[2]){
1061         linecpy(dst[1], src[1], height, srcStride[1]);
1062         linecpy(dst[2], src[2], height, srcStride[2]);
1063     }else{
1064         int y;
1065         for(y=0; y<height; y++){
1066             memcpy(&(dst[1][y*dstStride[1]]), &(src[1][y*srcStride[1]]), width);
1067             memcpy(&(dst[2][y*dstStride[2]]), &(src[2][y*srcStride[2]]), width);
1068         }
1069     }
1070 }