00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 
00038 
00039 
00040 
00041 
00042 
00043 
00044 
00045 
00046 
00047 
00048 
00049 
00050 
00051 
00052 
00053 
00054 
00055 
00056 
00057 
00058 
00059 
00060 
00061 
00062 
00063 
00064 
00065 
00066 
00067 
00068 
00069 
00070 
00071 
00072 
00073 
00074 
00075 
00076 #include "config.h"
00077 #include "libavutil/avutil.h"
00078 #include "libavutil/avassert.h"
00079 #include <inttypes.h>
00080 #include <stdio.h>
00081 #include <stdlib.h>
00082 #include <string.h>
00083 
00084 
00085 
00086 
00087 
00088 #include "postprocess.h"
00089 #include "postprocess_internal.h"
00090 #include "libavutil/avstring.h"
00091 
00092 unsigned postproc_version(void)
00093 {
00094     av_assert0(LIBPOSTPROC_VERSION_MICRO >= 100);
00095     return LIBPOSTPROC_VERSION_INT;
00096 }
00097 
00098 const char *postproc_configuration(void)
00099 {
00100     return FFMPEG_CONFIGURATION;
00101 }
00102 
00103 const char *postproc_license(void)
00104 {
00105 #define LICENSE_PREFIX "libpostproc license: "
00106     return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1;
00107 }
00108 
00109 #if HAVE_ALTIVEC_H
00110 #include <altivec.h>
00111 #endif
00112 
00113 #define GET_MODE_BUFFER_SIZE 500
00114 #define OPTIONS_ARRAY_SIZE 10
00115 #define BLOCK_SIZE 8
00116 #define TEMP_STRIDE 8
00117 
00118 
00119 #if ARCH_X86 && HAVE_INLINE_ASM
00120 DECLARE_ASM_CONST(8, uint64_t, w05)= 0x0005000500050005LL;
00121 DECLARE_ASM_CONST(8, uint64_t, w04)= 0x0004000400040004LL;
00122 DECLARE_ASM_CONST(8, uint64_t, w20)= 0x0020002000200020LL;
00123 DECLARE_ASM_CONST(8, uint64_t, b00)= 0x0000000000000000LL;
00124 DECLARE_ASM_CONST(8, uint64_t, b01)= 0x0101010101010101LL;
00125 DECLARE_ASM_CONST(8, uint64_t, b02)= 0x0202020202020202LL;
00126 DECLARE_ASM_CONST(8, uint64_t, b08)= 0x0808080808080808LL;
00127 DECLARE_ASM_CONST(8, uint64_t, b80)= 0x8080808080808080LL;
00128 #endif
00129 
00130 DECLARE_ASM_CONST(8, int, deringThreshold)= 20;
00131 
00132 
00133 static struct PPFilter filters[]=
00134 {
00135     {"hb", "hdeblock",              1, 1, 3, H_DEBLOCK},
00136     {"vb", "vdeblock",              1, 2, 4, V_DEBLOCK},
00137 
00138 
00139     {"h1", "x1hdeblock",            1, 1, 3, H_X1_FILTER},
00140     {"v1", "x1vdeblock",            1, 2, 4, V_X1_FILTER},
00141     {"ha", "ahdeblock",             1, 1, 3, H_A_DEBLOCK},
00142     {"va", "avdeblock",             1, 2, 4, V_A_DEBLOCK},
00143     {"dr", "dering",                1, 5, 6, DERING},
00144     {"al", "autolevels",            0, 1, 2, LEVEL_FIX},
00145     {"lb", "linblenddeint",         1, 1, 4, LINEAR_BLEND_DEINT_FILTER},
00146     {"li", "linipoldeint",          1, 1, 4, LINEAR_IPOL_DEINT_FILTER},
00147     {"ci", "cubicipoldeint",        1, 1, 4, CUBIC_IPOL_DEINT_FILTER},
00148     {"md", "mediandeint",           1, 1, 4, MEDIAN_DEINT_FILTER},
00149     {"fd", "ffmpegdeint",           1, 1, 4, FFMPEG_DEINT_FILTER},
00150     {"l5", "lowpass5",              1, 1, 4, LOWPASS5_DEINT_FILTER},
00151     {"tn", "tmpnoise",              1, 7, 8, TEMP_NOISE_FILTER},
00152     {"fq", "forcequant",            1, 0, 0, FORCE_QUANT},
00153     {"be", "bitexact",              1, 0, 0, BITEXACT},
00154     {NULL, NULL,0,0,0,0} 
00155 };
00156 
00157 static const char *replaceTable[]=
00158 {
00159     "default",      "hb:a,vb:a,dr:a",
00160     "de",           "hb:a,vb:a,dr:a",
00161     "fast",         "h1:a,v1:a,dr:a",
00162     "fa",           "h1:a,v1:a,dr:a",
00163     "ac",           "ha:a:128:7,va:a,dr:a",
00164     NULL 
00165 };
00166 
00167 
00168 #if ARCH_X86 && HAVE_INLINE_ASM
00169 static inline void prefetchnta(void *p)
00170 {
00171     __asm__ volatile(   "prefetchnta (%0)\n\t"
00172         : : "r" (p)
00173     );
00174 }
00175 
00176 static inline void prefetcht0(void *p)
00177 {
00178     __asm__ volatile(   "prefetcht0 (%0)\n\t"
00179         : : "r" (p)
00180     );
00181 }
00182 
00183 static inline void prefetcht1(void *p)
00184 {
00185     __asm__ volatile(   "prefetcht1 (%0)\n\t"
00186         : : "r" (p)
00187     );
00188 }
00189 
00190 static inline void prefetcht2(void *p)
00191 {
00192     __asm__ volatile(   "prefetcht2 (%0)\n\t"
00193         : : "r" (p)
00194     );
00195 }
00196 #endif
00197 
00198 
00199 
00200 
00204 static inline int isHorizDC_C(uint8_t src[], int stride, PPContext *c)
00205 {
00206     int numEq= 0;
00207     int y;
00208     const int dcOffset= ((c->nonBQP*c->ppMode.baseDcDiff)>>8) + 1;
00209     const int dcThreshold= dcOffset*2 + 1;
00210 
00211     for(y=0; y<BLOCK_SIZE; y++){
00212         if(((unsigned)(src[0] - src[1] + dcOffset)) < dcThreshold) numEq++;
00213         if(((unsigned)(src[1] - src[2] + dcOffset)) < dcThreshold) numEq++;
00214         if(((unsigned)(src[2] - src[3] + dcOffset)) < dcThreshold) numEq++;
00215         if(((unsigned)(src[3] - src[4] + dcOffset)) < dcThreshold) numEq++;
00216         if(((unsigned)(src[4] - src[5] + dcOffset)) < dcThreshold) numEq++;
00217         if(((unsigned)(src[5] - src[6] + dcOffset)) < dcThreshold) numEq++;
00218         if(((unsigned)(src[6] - src[7] + dcOffset)) < dcThreshold) numEq++;
00219         src+= stride;
00220     }
00221     return numEq > c->ppMode.flatnessThreshold;
00222 }
00223 
00227 static inline int isVertDC_C(uint8_t src[], int stride, PPContext *c)
00228 {
00229     int numEq= 0;
00230     int y;
00231     const int dcOffset= ((c->nonBQP*c->ppMode.baseDcDiff)>>8) + 1;
00232     const int dcThreshold= dcOffset*2 + 1;
00233 
00234     src+= stride*4; 
00235     for(y=0; y<BLOCK_SIZE-1; y++){
00236         if(((unsigned)(src[0] - src[0+stride] + dcOffset)) < dcThreshold) numEq++;
00237         if(((unsigned)(src[1] - src[1+stride] + dcOffset)) < dcThreshold) numEq++;
00238         if(((unsigned)(src[2] - src[2+stride] + dcOffset)) < dcThreshold) numEq++;
00239         if(((unsigned)(src[3] - src[3+stride] + dcOffset)) < dcThreshold) numEq++;
00240         if(((unsigned)(src[4] - src[4+stride] + dcOffset)) < dcThreshold) numEq++;
00241         if(((unsigned)(src[5] - src[5+stride] + dcOffset)) < dcThreshold) numEq++;
00242         if(((unsigned)(src[6] - src[6+stride] + dcOffset)) < dcThreshold) numEq++;
00243         if(((unsigned)(src[7] - src[7+stride] + dcOffset)) < dcThreshold) numEq++;
00244         src+= stride;
00245     }
00246     return numEq > c->ppMode.flatnessThreshold;
00247 }
00248 
00249 static inline int isHorizMinMaxOk_C(uint8_t src[], int stride, int QP)
00250 {
00251     int i;
00252     for(i=0; i<2; i++){
00253         if((unsigned)(src[0] - src[5] + 2*QP) > 4*QP) return 0;
00254         src += stride;
00255         if((unsigned)(src[2] - src[7] + 2*QP) > 4*QP) return 0;
00256         src += stride;
00257         if((unsigned)(src[4] - src[1] + 2*QP) > 4*QP) return 0;
00258         src += stride;
00259         if((unsigned)(src[6] - src[3] + 2*QP) > 4*QP) return 0;
00260         src += stride;
00261     }
00262     return 1;
00263 }
00264 
00265 static inline int isVertMinMaxOk_C(uint8_t src[], int stride, int QP)
00266 {
00267     int x;
00268     src+= stride*4;
00269     for(x=0; x<BLOCK_SIZE; x+=4){
00270         if((unsigned)(src[  x + 0*stride] - src[  x + 5*stride] + 2*QP) > 4*QP) return 0;
00271         if((unsigned)(src[1+x + 2*stride] - src[1+x + 7*stride] + 2*QP) > 4*QP) return 0;
00272         if((unsigned)(src[2+x + 4*stride] - src[2+x + 1*stride] + 2*QP) > 4*QP) return 0;
00273         if((unsigned)(src[3+x + 6*stride] - src[3+x + 3*stride] + 2*QP) > 4*QP) return 0;
00274     }
00275     return 1;
00276 }
00277 
00278 static inline int horizClassify_C(uint8_t src[], int stride, PPContext *c)
00279 {
00280     if( isHorizDC_C(src, stride, c) ){
00281         if( isHorizMinMaxOk_C(src, stride, c->QP) )
00282             return 1;
00283         else
00284             return 0;
00285     }else{
00286         return 2;
00287     }
00288 }
00289 
00290 static inline int vertClassify_C(uint8_t src[], int stride, PPContext *c)
00291 {
00292     if( isVertDC_C(src, stride, c) ){
00293         if( isVertMinMaxOk_C(src, stride, c->QP) )
00294             return 1;
00295         else
00296             return 0;
00297     }else{
00298         return 2;
00299     }
00300 }
00301 
00302 static inline void doHorizDefFilter_C(uint8_t dst[], int stride, PPContext *c)
00303 {
00304     int y;
00305     for(y=0; y<BLOCK_SIZE; y++){
00306         const int middleEnergy= 5*(dst[4] - dst[3]) + 2*(dst[2] - dst[5]);
00307 
00308         if(FFABS(middleEnergy) < 8*c->QP){
00309             const int q=(dst[3] - dst[4])/2;
00310             const int leftEnergy=  5*(dst[2] - dst[1]) + 2*(dst[0] - dst[3]);
00311             const int rightEnergy= 5*(dst[6] - dst[5]) + 2*(dst[4] - dst[7]);
00312 
00313             int d= FFABS(middleEnergy) - FFMIN( FFABS(leftEnergy), FFABS(rightEnergy) );
00314             d= FFMAX(d, 0);
00315 
00316             d= (5*d + 32) >> 6;
00317             d*= FFSIGN(-middleEnergy);
00318 
00319             if(q>0)
00320             {
00321                 d= d<0 ? 0 : d;
00322                 d= d>q ? q : d;
00323             }
00324             else
00325             {
00326                 d= d>0 ? 0 : d;
00327                 d= d<q ? q : d;
00328             }
00329 
00330             dst[3]-= d;
00331             dst[4]+= d;
00332         }
00333         dst+= stride;
00334     }
00335 }
00336 
00341 static inline void doHorizLowPass_C(uint8_t dst[], int stride, PPContext *c)
00342 {
00343     int y;
00344     for(y=0; y<BLOCK_SIZE; y++){
00345         const int first= FFABS(dst[-1] - dst[0]) < c->QP ? dst[-1] : dst[0];
00346         const int last= FFABS(dst[8] - dst[7]) < c->QP ? dst[8] : dst[7];
00347 
00348         int sums[10];
00349         sums[0] = 4*first + dst[0] + dst[1] + dst[2] + 4;
00350         sums[1] = sums[0] - first  + dst[3];
00351         sums[2] = sums[1] - first  + dst[4];
00352         sums[3] = sums[2] - first  + dst[5];
00353         sums[4] = sums[3] - first  + dst[6];
00354         sums[5] = sums[4] - dst[0] + dst[7];
00355         sums[6] = sums[5] - dst[1] + last;
00356         sums[7] = sums[6] - dst[2] + last;
00357         sums[8] = sums[7] - dst[3] + last;
00358         sums[9] = sums[8] - dst[4] + last;
00359 
00360         dst[0]= (sums[0] + sums[2] + 2*dst[0])>>4;
00361         dst[1]= (sums[1] + sums[3] + 2*dst[1])>>4;
00362         dst[2]= (sums[2] + sums[4] + 2*dst[2])>>4;
00363         dst[3]= (sums[3] + sums[5] + 2*dst[3])>>4;
00364         dst[4]= (sums[4] + sums[6] + 2*dst[4])>>4;
00365         dst[5]= (sums[5] + sums[7] + 2*dst[5])>>4;
00366         dst[6]= (sums[6] + sums[8] + 2*dst[6])>>4;
00367         dst[7]= (sums[7] + sums[9] + 2*dst[7])>>4;
00368 
00369         dst+= stride;
00370     }
00371 }
00372 
00381 static inline void horizX1Filter(uint8_t *src, int stride, int QP)
00382 {
00383     int y;
00384     static uint64_t *lut= NULL;
00385     if(lut==NULL)
00386     {
00387         int i;
00388         lut = av_malloc(256*8);
00389         for(i=0; i<256; i++)
00390         {
00391             int v= i < 128 ? 2*i : 2*(i-256);
00392 
00393 
00394 
00395 
00396 
00397 
00398 
00399 
00400             uint64_t a= (v/16)   & 0xFF;
00401             uint64_t b= (v*3/16) & 0xFF;
00402             uint64_t c= (v*5/16) & 0xFF;
00403             uint64_t d= (7*v/16) & 0xFF;
00404             uint64_t A= (0x100 - a)&0xFF;
00405             uint64_t B= (0x100 - b)&0xFF;
00406             uint64_t C= (0x100 - c)&0xFF;
00407             uint64_t D= (0x100 - c)&0xFF;
00408 
00409             lut[i]   = (a<<56) | (b<<48) | (c<<40) | (d<<32) |
00410                        (D<<24) | (C<<16) | (B<<8)  | (A);
00411             
00412         }
00413     }
00414 
00415     for(y=0; y<BLOCK_SIZE; y++){
00416         int a= src[1] - src[2];
00417         int b= src[3] - src[4];
00418         int c= src[5] - src[6];
00419 
00420         int d= FFMAX(FFABS(b) - (FFABS(a) + FFABS(c))/2, 0);
00421 
00422         if(d < QP){
00423             int v = d * FFSIGN(-b);
00424 
00425             src[1] +=v/8;
00426             src[2] +=v/4;
00427             src[3] +=3*v/8;
00428             src[4] -=3*v/8;
00429             src[5] -=v/4;
00430             src[6] -=v/8;
00431         }
00432         src+=stride;
00433     }
00434 }
00435 
00439 static av_always_inline void do_a_deblock_C(uint8_t *src, int step, int stride, PPContext *c){
00440     int y;
00441     const int QP= c->QP;
00442     const int dcOffset= ((c->nonBQP*c->ppMode.baseDcDiff)>>8) + 1;
00443     const int dcThreshold= dcOffset*2 + 1;
00444 
00445     src+= step*4; 
00446     for(y=0; y<8; y++){
00447         int numEq= 0;
00448 
00449         if(((unsigned)(src[-1*step] - src[0*step] + dcOffset)) < dcThreshold) numEq++;
00450         if(((unsigned)(src[ 0*step] - src[1*step] + dcOffset)) < dcThreshold) numEq++;
00451         if(((unsigned)(src[ 1*step] - src[2*step] + dcOffset)) < dcThreshold) numEq++;
00452         if(((unsigned)(src[ 2*step] - src[3*step] + dcOffset)) < dcThreshold) numEq++;
00453         if(((unsigned)(src[ 3*step] - src[4*step] + dcOffset)) < dcThreshold) numEq++;
00454         if(((unsigned)(src[ 4*step] - src[5*step] + dcOffset)) < dcThreshold) numEq++;
00455         if(((unsigned)(src[ 5*step] - src[6*step] + dcOffset)) < dcThreshold) numEq++;
00456         if(((unsigned)(src[ 6*step] - src[7*step] + dcOffset)) < dcThreshold) numEq++;
00457         if(((unsigned)(src[ 7*step] - src[8*step] + dcOffset)) < dcThreshold) numEq++;
00458         if(numEq > c->ppMode.flatnessThreshold){
00459             int min, max, x;
00460 
00461             if(src[0] > src[step]){
00462                 max= src[0];
00463                 min= src[step];
00464             }else{
00465                 max= src[step];
00466                 min= src[0];
00467             }
00468             for(x=2; x<8; x+=2){
00469                 if(src[x*step] > src[(x+1)*step]){
00470                         if(src[x    *step] > max) max= src[ x   *step];
00471                         if(src[(x+1)*step] < min) min= src[(x+1)*step];
00472                 }else{
00473                         if(src[(x+1)*step] > max) max= src[(x+1)*step];
00474                         if(src[ x   *step] < min) min= src[ x   *step];
00475                 }
00476             }
00477             if(max-min < 2*QP){
00478                 const int first= FFABS(src[-1*step] - src[0]) < QP ? src[-1*step] : src[0];
00479                 const int last= FFABS(src[8*step] - src[7*step]) < QP ? src[8*step] : src[7*step];
00480 
00481                 int sums[10];
00482                 sums[0] = 4*first + src[0*step] + src[1*step] + src[2*step] + 4;
00483                 sums[1] = sums[0] - first       + src[3*step];
00484                 sums[2] = sums[1] - first       + src[4*step];
00485                 sums[3] = sums[2] - first       + src[5*step];
00486                 sums[4] = sums[3] - first       + src[6*step];
00487                 sums[5] = sums[4] - src[0*step] + src[7*step];
00488                 sums[6] = sums[5] - src[1*step] + last;
00489                 sums[7] = sums[6] - src[2*step] + last;
00490                 sums[8] = sums[7] - src[3*step] + last;
00491                 sums[9] = sums[8] - src[4*step] + last;
00492 
00493                 src[0*step]= (sums[0] + sums[2] + 2*src[0*step])>>4;
00494                 src[1*step]= (sums[1] + sums[3] + 2*src[1*step])>>4;
00495                 src[2*step]= (sums[2] + sums[4] + 2*src[2*step])>>4;
00496                 src[3*step]= (sums[3] + sums[5] + 2*src[3*step])>>4;
00497                 src[4*step]= (sums[4] + sums[6] + 2*src[4*step])>>4;
00498                 src[5*step]= (sums[5] + sums[7] + 2*src[5*step])>>4;
00499                 src[6*step]= (sums[6] + sums[8] + 2*src[6*step])>>4;
00500                 src[7*step]= (sums[7] + sums[9] + 2*src[7*step])>>4;
00501             }
00502         }else{
00503             const int middleEnergy= 5*(src[4*step] - src[3*step]) + 2*(src[2*step] - src[5*step]);
00504 
00505             if(FFABS(middleEnergy) < 8*QP){
00506                 const int q=(src[3*step] - src[4*step])/2;
00507                 const int leftEnergy=  5*(src[2*step] - src[1*step]) + 2*(src[0*step] - src[3*step]);
00508                 const int rightEnergy= 5*(src[6*step] - src[5*step]) + 2*(src[4*step] - src[7*step]);
00509 
00510                 int d= FFABS(middleEnergy) - FFMIN( FFABS(leftEnergy), FFABS(rightEnergy) );
00511                 d= FFMAX(d, 0);
00512 
00513                 d= (5*d + 32) >> 6;
00514                 d*= FFSIGN(-middleEnergy);
00515 
00516                 if(q>0){
00517                     d= d<0 ? 0 : d;
00518                     d= d>q ? q : d;
00519                 }else{
00520                     d= d>0 ? 0 : d;
00521                     d= d<q ? q : d;
00522                 }
00523 
00524                 src[3*step]-= d;
00525                 src[4*step]+= d;
00526             }
00527         }
00528 
00529         src += stride;
00530     }
00531 
00532 
00533 
00534 
00535 
00536 }
00537 
00538 
00539 
00540 
00541 #define COMPILE_C
00542 
00543 #if HAVE_ALTIVEC
00544 #define COMPILE_ALTIVEC
00545 #endif //HAVE_ALTIVEC
00546 
00547 #if ARCH_X86 && HAVE_INLINE_ASM
00548 
00549 #if (HAVE_MMX_INLINE && !HAVE_AMD3DNOW_INLINE && !HAVE_MMXEXT_INLINE) || CONFIG_RUNTIME_CPUDETECT
00550 #define COMPILE_MMX
00551 #endif
00552 
00553 #if HAVE_MMXEXT_INLINE || CONFIG_RUNTIME_CPUDETECT
00554 #define COMPILE_MMX2
00555 #endif
00556 
00557 #if (HAVE_AMD3DNOW_INLINE && !HAVE_MMXEXT_INLINE) || CONFIG_RUNTIME_CPUDETECT
00558 #define COMPILE_3DNOW
00559 #endif
00560 #endif 
00561 
00562 #undef HAVE_MMX_INLINE
00563 #define HAVE_MMX_INLINE 0
00564 #undef HAVE_MMXEXT_INLINE
00565 #define HAVE_MMXEXT_INLINE 0
00566 #undef HAVE_AMD3DNOW_INLINE
00567 #define HAVE_AMD3DNOW_INLINE 0
00568 #undef HAVE_ALTIVEC
00569 #define HAVE_ALTIVEC 0
00570 
00571 #ifdef COMPILE_C
00572 #define RENAME(a) a ## _C
00573 #include "postprocess_template.c"
00574 #endif
00575 
00576 #ifdef COMPILE_ALTIVEC
00577 #undef RENAME
00578 #undef HAVE_ALTIVEC
00579 #define HAVE_ALTIVEC 1
00580 #define RENAME(a) a ## _altivec
00581 #include "postprocess_altivec_template.c"
00582 #include "postprocess_template.c"
00583 #endif
00584 
00585 
00586 #ifdef COMPILE_MMX
00587 #undef RENAME
00588 #undef HAVE_MMX_INLINE
00589 #define HAVE_MMX_INLINE 1
00590 #define RENAME(a) a ## _MMX
00591 #include "postprocess_template.c"
00592 #endif
00593 
00594 
00595 #ifdef COMPILE_MMX2
00596 #undef RENAME
00597 #undef HAVE_MMX_INLINE
00598 #undef HAVE_MMXEXT_INLINE
00599 #define HAVE_MMX_INLINE 1
00600 #define HAVE_MMXEXT_INLINE 1
00601 #define RENAME(a) a ## _MMX2
00602 #include "postprocess_template.c"
00603 #endif
00604 
00605 
00606 #ifdef COMPILE_3DNOW
00607 #undef RENAME
00608 #undef HAVE_MMX_INLINE
00609 #undef HAVE_MMXEXT_INLINE
00610 #undef HAVE_AMD3DNOW_INLINE
00611 #define HAVE_MMX_INLINE 1
00612 #define HAVE_MMXEXT_INLINE 0
00613 #define HAVE_AMD3DNOW_INLINE 1
00614 #define RENAME(a) a ## _3DNow
00615 #include "postprocess_template.c"
00616 #endif
00617 
00618 
00619 
00620 static inline void postProcess(const uint8_t src[], int srcStride, uint8_t dst[], int dstStride, int width, int height,
00621         const QP_STORE_T QPs[], int QPStride, int isColor, pp_mode *vm, pp_context *vc)
00622 {
00623     PPContext *c= (PPContext *)vc;
00624     PPMode *ppMode= (PPMode *)vm;
00625     c->ppMode= *ppMode; 
00626 
00627     if(ppMode->lumMode & BITEXACT) {
00628         postProcess_C(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
00629         return;
00630     }
00631 
00632     
00633     
00634     
00635 #if CONFIG_RUNTIME_CPUDETECT
00636 #if ARCH_X86 && HAVE_INLINE_ASM
00637     
00638     if(c->cpuCaps & PP_CPU_CAPS_MMX2)
00639         postProcess_MMX2(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
00640     else if(c->cpuCaps & PP_CPU_CAPS_3DNOW)
00641         postProcess_3DNow(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
00642     else if(c->cpuCaps & PP_CPU_CAPS_MMX)
00643         postProcess_MMX(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
00644     else
00645         postProcess_C(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
00646 #else
00647 #if HAVE_ALTIVEC
00648     if(c->cpuCaps & PP_CPU_CAPS_ALTIVEC)
00649             postProcess_altivec(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
00650     else
00651 #endif
00652             postProcess_C(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
00653 #endif
00654 #else 
00655 #if   HAVE_MMXEXT_INLINE
00656             postProcess_MMX2(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
00657 #elif HAVE_AMD3DNOW_INLINE
00658             postProcess_3DNow(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
00659 #elif HAVE_MMX_INLINE
00660             postProcess_MMX(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
00661 #elif HAVE_ALTIVEC
00662             postProcess_altivec(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
00663 #else
00664             postProcess_C(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
00665 #endif
00666 #endif 
00667 }
00668 
00669 
00670 
00671 
00672 
00673 
00674 #if LIBPOSTPROC_VERSION_INT < (52<<16)
00675 const char *const pp_help=
00676 #else
00677 const char pp_help[] =
00678 #endif
00679 "Available postprocessing filters:\n"
00680 "Filters                        Options\n"
00681 "short  long name       short   long option     Description\n"
00682 "*      *               a       autoq           CPU power dependent enabler\n"
00683 "                       c       chrom           chrominance filtering enabled\n"
00684 "                       y       nochrom         chrominance filtering disabled\n"
00685 "                       n       noluma          luma filtering disabled\n"
00686 "hb     hdeblock        (2 threshold)           horizontal deblocking filter\n"
00687 "       1. difference factor: default=32, higher -> more deblocking\n"
00688 "       2. flatness threshold: default=39, lower -> more deblocking\n"
00689 "                       the h & v deblocking filters share these\n"
00690 "                       so you can't set different thresholds for h / v\n"
00691 "vb     vdeblock        (2 threshold)           vertical deblocking filter\n"
00692 "ha     hadeblock       (2 threshold)           horizontal deblocking filter\n"
00693 "va     vadeblock       (2 threshold)           vertical deblocking filter\n"
00694 "h1     x1hdeblock                              experimental h deblock filter 1\n"
00695 "v1     x1vdeblock                              experimental v deblock filter 1\n"
00696 "dr     dering                                  deringing filter\n"
00697 "al     autolevels                              automatic brightness / contrast\n"
00698 "                       f        fullyrange     stretch luminance to (0..255)\n"
00699 "lb     linblenddeint                           linear blend deinterlacer\n"
00700 "li     linipoldeint                            linear interpolating deinterlace\n"
00701 "ci     cubicipoldeint                          cubic interpolating deinterlacer\n"
00702 "md     mediandeint                             median deinterlacer\n"
00703 "fd     ffmpegdeint                             ffmpeg deinterlacer\n"
00704 "l5     lowpass5                                FIR lowpass deinterlacer\n"
00705 "de     default                                 hb:a,vb:a,dr:a\n"
00706 "fa     fast                                    h1:a,v1:a,dr:a\n"
00707 "ac                                             ha:a:128:7,va:a,dr:a\n"
00708 "tn     tmpnoise        (3 threshold)           temporal noise reducer\n"
00709 "                     1. <= 2. <= 3.            larger -> stronger filtering\n"
00710 "fq     forceQuant      <quantizer>             force quantizer\n"
00711 "Usage:\n"
00712 "<filterName>[:<option>[:<option>...]][[,|/][-]<filterName>[:<option>...]]...\n"
00713 "long form example:\n"
00714 "vdeblock:autoq/hdeblock:autoq/linblenddeint    default,-vdeblock\n"
00715 "short form example:\n"
00716 "vb:a/hb:a/lb                                   de,-vb\n"
00717 "more examples:\n"
00718 "tn:64:128:256\n"
00719 "\n"
00720 ;
00721 
00722 pp_mode *pp_get_mode_by_name_and_quality(const char *name, int quality)
00723 {
00724     char temp[GET_MODE_BUFFER_SIZE];
00725     char *p= temp;
00726     static const char filterDelimiters[] = ",/";
00727     static const char optionDelimiters[] = ":";
00728     struct PPMode *ppMode;
00729     char *filterToken;
00730 
00731     if (!name)  {
00732         av_log(NULL, AV_LOG_ERROR, "pp: Missing argument\n");
00733         return NULL;
00734     }
00735 
00736     if (!strcmp(name, "help")) {
00737         const char *p;
00738         for (p = pp_help; strchr(p, '\n'); p = strchr(p, '\n') + 1) {
00739             av_strlcpy(temp, p, FFMIN(sizeof(temp), strchr(p, '\n') - p + 2));
00740             av_log(NULL, AV_LOG_INFO, "%s", temp);
00741         }
00742         return NULL;
00743     }
00744 
00745     ppMode= av_malloc(sizeof(PPMode));
00746 
00747     ppMode->lumMode= 0;
00748     ppMode->chromMode= 0;
00749     ppMode->maxTmpNoise[0]= 700;
00750     ppMode->maxTmpNoise[1]= 1500;
00751     ppMode->maxTmpNoise[2]= 3000;
00752     ppMode->maxAllowedY= 234;
00753     ppMode->minAllowedY= 16;
00754     ppMode->baseDcDiff= 256/8;
00755     ppMode->flatnessThreshold= 56-16-1;
00756     ppMode->maxClippedThreshold= 0.01;
00757     ppMode->error=0;
00758 
00759     memset(temp, 0, GET_MODE_BUFFER_SIZE);
00760     av_strlcpy(temp, name, GET_MODE_BUFFER_SIZE - 1);
00761 
00762     av_log(NULL, AV_LOG_DEBUG, "pp: %s\n", name);
00763 
00764     for(;;){
00765         char *filterName;
00766         int q= 1000000; 
00767         int chrom=-1;
00768         int luma=-1;
00769         char *option;
00770         char *options[OPTIONS_ARRAY_SIZE];
00771         int i;
00772         int filterNameOk=0;
00773         int numOfUnknownOptions=0;
00774         int enable=1; 
00775 
00776         filterToken= strtok(p, filterDelimiters);
00777         if(filterToken == NULL) break;
00778         p+= strlen(filterToken) + 1; 
00779         filterName= strtok(filterToken, optionDelimiters);
00780         av_log(NULL, AV_LOG_DEBUG, "pp: %s::%s\n", filterToken, filterName);
00781 
00782         if(*filterName == '-'){
00783             enable=0;
00784             filterName++;
00785         }
00786 
00787         for(;;){ 
00788             option= strtok(NULL, optionDelimiters);
00789             if(option == NULL) break;
00790 
00791             av_log(NULL, AV_LOG_DEBUG, "pp: option: %s\n", option);
00792             if(!strcmp("autoq", option) || !strcmp("a", option)) q= quality;
00793             else if(!strcmp("nochrom", option) || !strcmp("y", option)) chrom=0;
00794             else if(!strcmp("chrom", option) || !strcmp("c", option)) chrom=1;
00795             else if(!strcmp("noluma", option) || !strcmp("n", option)) luma=0;
00796             else{
00797                 options[numOfUnknownOptions] = option;
00798                 numOfUnknownOptions++;
00799             }
00800             if(numOfUnknownOptions >= OPTIONS_ARRAY_SIZE-1) break;
00801         }
00802         options[numOfUnknownOptions] = NULL;
00803 
00804         
00805         for(i=0; replaceTable[2*i]!=NULL; i++){
00806             if(!strcmp(replaceTable[2*i], filterName)){
00807                 int newlen= strlen(replaceTable[2*i + 1]);
00808                 int plen;
00809                 int spaceLeft;
00810 
00811                 p--, *p=',';
00812 
00813                 plen= strlen(p);
00814                 spaceLeft= p - temp + plen;
00815                 if(spaceLeft + newlen  >= GET_MODE_BUFFER_SIZE - 1){
00816                     ppMode->error++;
00817                     break;
00818                 }
00819                 memmove(p + newlen, p, plen+1);
00820                 memcpy(p, replaceTable[2*i + 1], newlen);
00821                 filterNameOk=1;
00822             }
00823         }
00824 
00825         for(i=0; filters[i].shortName!=NULL; i++){
00826             if(   !strcmp(filters[i].longName, filterName)
00827                || !strcmp(filters[i].shortName, filterName)){
00828                 ppMode->lumMode &= ~filters[i].mask;
00829                 ppMode->chromMode &= ~filters[i].mask;
00830 
00831                 filterNameOk=1;
00832                 if(!enable) break; 
00833 
00834                 if(q >= filters[i].minLumQuality && luma)
00835                     ppMode->lumMode|= filters[i].mask;
00836                 if(chrom==1 || (chrom==-1 && filters[i].chromDefault))
00837                     if(q >= filters[i].minChromQuality)
00838                             ppMode->chromMode|= filters[i].mask;
00839 
00840                 if(filters[i].mask == LEVEL_FIX){
00841                     int o;
00842                     ppMode->minAllowedY= 16;
00843                     ppMode->maxAllowedY= 234;
00844                     for(o=0; options[o]!=NULL; o++){
00845                         if(  !strcmp(options[o],"fullyrange")
00846                            ||!strcmp(options[o],"f")){
00847                             ppMode->minAllowedY= 0;
00848                             ppMode->maxAllowedY= 255;
00849                             numOfUnknownOptions--;
00850                         }
00851                     }
00852                 }
00853                 else if(filters[i].mask == TEMP_NOISE_FILTER)
00854                 {
00855                     int o;
00856                     int numOfNoises=0;
00857 
00858                     for(o=0; options[o]!=NULL; o++){
00859                         char *tail;
00860                         ppMode->maxTmpNoise[numOfNoises]=
00861                             strtol(options[o], &tail, 0);
00862                         if(tail!=options[o]){
00863                             numOfNoises++;
00864                             numOfUnknownOptions--;
00865                             if(numOfNoises >= 3) break;
00866                         }
00867                     }
00868                 }
00869                 else if(filters[i].mask == V_DEBLOCK   || filters[i].mask == H_DEBLOCK
00870                      || filters[i].mask == V_A_DEBLOCK || filters[i].mask == H_A_DEBLOCK){
00871                     int o;
00872 
00873                     for(o=0; options[o]!=NULL && o<2; o++){
00874                         char *tail;
00875                         int val= strtol(options[o], &tail, 0);
00876                         if(tail==options[o]) break;
00877 
00878                         numOfUnknownOptions--;
00879                         if(o==0) ppMode->baseDcDiff= val;
00880                         else ppMode->flatnessThreshold= val;
00881                     }
00882                 }
00883                 else if(filters[i].mask == FORCE_QUANT){
00884                     int o;
00885                     ppMode->forcedQuant= 15;
00886 
00887                     for(o=0; options[o]!=NULL && o<1; o++){
00888                         char *tail;
00889                         int val= strtol(options[o], &tail, 0);
00890                         if(tail==options[o]) break;
00891 
00892                         numOfUnknownOptions--;
00893                         ppMode->forcedQuant= val;
00894                     }
00895                 }
00896             }
00897         }
00898         if(!filterNameOk) ppMode->error++;
00899         ppMode->error += numOfUnknownOptions;
00900     }
00901 
00902     av_log(NULL, AV_LOG_DEBUG, "pp: lumMode=%X, chromMode=%X\n", ppMode->lumMode, ppMode->chromMode);
00903     if(ppMode->error){
00904         av_log(NULL, AV_LOG_ERROR, "%d errors in postprocess string \"%s\"\n", ppMode->error, name);
00905         av_free(ppMode);
00906         return NULL;
00907     }
00908     return ppMode;
00909 }
00910 
00911 void pp_free_mode(pp_mode *mode){
00912     av_free(mode);
00913 }
00914 
00915 static void reallocAlign(void **p, int alignment, int size){
00916     av_free(*p);
00917     *p= av_mallocz(size);
00918 }
00919 
00920 static void reallocBuffers(PPContext *c, int width, int height, int stride, int qpStride){
00921     int mbWidth = (width+15)>>4;
00922     int mbHeight= (height+15)>>4;
00923     int i;
00924 
00925     c->stride= stride;
00926     c->qpStride= qpStride;
00927 
00928     reallocAlign((void **)&c->tempDst, 8, stride*24);
00929     reallocAlign((void **)&c->tempSrc, 8, stride*24);
00930     reallocAlign((void **)&c->tempBlocks, 8, 2*16*8);
00931     reallocAlign((void **)&c->yHistogram, 8, 256*sizeof(uint64_t));
00932     for(i=0; i<256; i++)
00933             c->yHistogram[i]= width*height/64*15/256;
00934 
00935     for(i=0; i<3; i++){
00936         
00937         reallocAlign((void **)&c->tempBlurred[i], 8, stride*mbHeight*16 + 17*1024);
00938         reallocAlign((void **)&c->tempBlurredPast[i], 8, 256*((height+7)&(~7))/2 + 17*1024);
00939     }
00940 
00941     reallocAlign((void **)&c->deintTemp, 8, 2*width+32);
00942     reallocAlign((void **)&c->nonBQPTable, 8, qpStride*mbHeight*sizeof(QP_STORE_T));
00943     reallocAlign((void **)&c->stdQPTable, 8, qpStride*mbHeight*sizeof(QP_STORE_T));
00944     reallocAlign((void **)&c->forcedQPTable, 8, mbWidth*sizeof(QP_STORE_T));
00945 }
00946 
00947 static const char * context_to_name(void * ptr) {
00948     return "postproc";
00949 }
00950 
00951 static const AVClass av_codec_context_class = { "Postproc", context_to_name, NULL };
00952 
00953 pp_context *pp_get_context(int width, int height, int cpuCaps){
00954     PPContext *c= av_malloc(sizeof(PPContext));
00955     int stride= FFALIGN(width, 16);  
00956     int qpStride= (width+15)/16 + 2; 
00957 
00958     memset(c, 0, sizeof(PPContext));
00959     c->av_class = &av_codec_context_class;
00960     c->cpuCaps= cpuCaps;
00961     if(cpuCaps&PP_FORMAT){
00962         c->hChromaSubSample= cpuCaps&0x3;
00963         c->vChromaSubSample= (cpuCaps>>4)&0x3;
00964     }else{
00965         c->hChromaSubSample= 1;
00966         c->vChromaSubSample= 1;
00967     }
00968 
00969     reallocBuffers(c, width, height, stride, qpStride);
00970 
00971     c->frameNum=-1;
00972 
00973     return c;
00974 }
00975 
00976 void pp_free_context(void *vc){
00977     PPContext *c = (PPContext*)vc;
00978     int i;
00979 
00980     for(i=0; i<3; i++) av_free(c->tempBlurred[i]);
00981     for(i=0; i<3; i++) av_free(c->tempBlurredPast[i]);
00982 
00983     av_free(c->tempBlocks);
00984     av_free(c->yHistogram);
00985     av_free(c->tempDst);
00986     av_free(c->tempSrc);
00987     av_free(c->deintTemp);
00988     av_free(c->stdQPTable);
00989     av_free(c->nonBQPTable);
00990     av_free(c->forcedQPTable);
00991 
00992     memset(c, 0, sizeof(PPContext));
00993 
00994     av_free(c);
00995 }
00996 
00997 void  pp_postprocess(const uint8_t * src[3], const int srcStride[3],
00998                      uint8_t * dst[3], const int dstStride[3],
00999                      int width, int height,
01000                      const QP_STORE_T *QP_store,  int QPStride,
01001                      pp_mode *vm,  void *vc, int pict_type)
01002 {
01003     int mbWidth = (width+15)>>4;
01004     int mbHeight= (height+15)>>4;
01005     PPMode *mode = (PPMode*)vm;
01006     PPContext *c = (PPContext*)vc;
01007     int minStride= FFMAX(FFABS(srcStride[0]), FFABS(dstStride[0]));
01008     int absQPStride = FFABS(QPStride);
01009 
01010     
01011     if(c->stride < minStride || c->qpStride < absQPStride)
01012         reallocBuffers(c, width, height,
01013                        FFMAX(minStride, c->stride),
01014                        FFMAX(c->qpStride, absQPStride));
01015 
01016     if(QP_store==NULL || (mode->lumMode & FORCE_QUANT)){
01017         int i;
01018         QP_store= c->forcedQPTable;
01019         absQPStride = QPStride = 0;
01020         if(mode->lumMode & FORCE_QUANT)
01021             for(i=0; i<mbWidth; i++) c->forcedQPTable[i]= mode->forcedQuant;
01022         else
01023             for(i=0; i<mbWidth; i++) c->forcedQPTable[i]= 1;
01024     }
01025 
01026     if(pict_type & PP_PICT_TYPE_QP2){
01027         int i;
01028         const int count= mbHeight * absQPStride;
01029         for(i=0; i<(count>>2); i++){
01030             ((uint32_t*)c->stdQPTable)[i] = (((const uint32_t*)QP_store)[i]>>1) & 0x7F7F7F7F;
01031         }
01032         for(i<<=2; i<count; i++){
01033             c->stdQPTable[i] = QP_store[i]>>1;
01034         }
01035         QP_store= c->stdQPTable;
01036         QPStride= absQPStride;
01037     }
01038 
01039     if(0){
01040         int x,y;
01041         for(y=0; y<mbHeight; y++){
01042             for(x=0; x<mbWidth; x++){
01043                 av_log(c, AV_LOG_INFO, "%2d ", QP_store[x + y*QPStride]);
01044             }
01045             av_log(c, AV_LOG_INFO, "\n");
01046         }
01047         av_log(c, AV_LOG_INFO, "\n");
01048     }
01049 
01050     if((pict_type&7)!=3){
01051         if (QPStride >= 0){
01052             int i;
01053             const int count= mbHeight * QPStride;
01054             for(i=0; i<(count>>2); i++){
01055                 ((uint32_t*)c->nonBQPTable)[i] = ((const uint32_t*)QP_store)[i] & 0x3F3F3F3F;
01056             }
01057             for(i<<=2; i<count; i++){
01058                 c->nonBQPTable[i] = QP_store[i] & 0x3F;
01059             }
01060         } else {
01061             int i,j;
01062             for(i=0; i<mbHeight; i++) {
01063                 for(j=0; j<absQPStride; j++) {
01064                     c->nonBQPTable[i*absQPStride+j] = QP_store[i*QPStride+j] & 0x3F;
01065                 }
01066             }
01067         }
01068     }
01069 
01070     av_log(c, AV_LOG_DEBUG, "using npp filters 0x%X/0x%X\n",
01071            mode->lumMode, mode->chromMode);
01072 
01073     postProcess(src[0], srcStride[0], dst[0], dstStride[0],
01074                 width, height, QP_store, QPStride, 0, mode, c);
01075 
01076     width  = (width )>>c->hChromaSubSample;
01077     height = (height)>>c->vChromaSubSample;
01078 
01079     if(mode->chromMode){
01080         postProcess(src[1], srcStride[1], dst[1], dstStride[1],
01081                     width, height, QP_store, QPStride, 1, mode, c);
01082         postProcess(src[2], srcStride[2], dst[2], dstStride[2],
01083                     width, height, QP_store, QPStride, 2, mode, c);
01084     }
01085     else if(srcStride[1] == dstStride[1] && srcStride[2] == dstStride[2]){
01086         linecpy(dst[1], src[1], height, srcStride[1]);
01087         linecpy(dst[2], src[2], height, srcStride[2]);
01088     }else{
01089         int y;
01090         for(y=0; y<height; y++){
01091             memcpy(&(dst[1][y*dstStride[1]]), &(src[1][y*srcStride[1]]), width);
01092             memcpy(&(dst[2][y*dstStride[2]]), &(src[2][y*srcStride[2]]), width);
01093         }
01094     }
01095 }