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