/* Copyright (C) 2001-2002 Michael Niedermayer (michaelni@gmx.at) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* C MMX MMX2 3DNow isVertDC Ec Ec isVertMinMaxOk Ec Ec doVertLowPass E e e doVertDefFilter Ec Ec e e isHorizDC Ec Ec isHorizMinMaxOk a E doHorizLowPass E e e doHorizDefFilter Ec Ec e e deRing E e e* Vertical RKAlgo1 E a a Horizontal RKAlgo1 a a Vertical X1# a E E Horizontal X1# a E E LinIpolDeinterlace e E E* CubicIpolDeinterlace a e e* LinBlendDeinterlace e E E* MedianDeinterlace# Ec Ec TempDeNoiser# E e e * i dont have a 3dnow CPU -> its untested, but noone said it doesnt work so it seems to work # more or less selfinvented filters so the exactness isnt too meaningfull E = Exact implementation e = allmost exact implementation (slightly different rounding,...) a = alternative / approximate impl c = checked against the other implementations (-vo md5) */ /* TODO: reduce the time wasted on the mem transfer unroll stuff if instructions depend too much on the prior one move YScale thing to the end instead of fixing QP write a faster and higher quality deblocking filter :) make the mainloop more flexible (variable number of blocks at once (the if/else stuff per block is slowing things down) compare the quality & speed of all filters split this huge file optimize c versions try to unroll inner for(x=0 ... loop to avoid these damn if(x ... checks ... */ //Changelog: use the CVS log #include "../config.h" #include #include #include #include #ifdef HAVE_MALLOC_H #include #endif //#undef HAVE_MMX2 //#define HAVE_3DNOW //#undef HAVE_MMX //#undef ARCH_X86 //#define DEBUG_BRIGHTNESS #ifndef PIC #include "../libvo/fastmemcpy.h" #endif #include "postprocess.h" #include "postprocess_internal.h" #include "../mangle.h" #define MIN(a,b) ((a) > (b) ? (b) : (a)) #define MAX(a,b) ((a) < (b) ? (b) : (a)) #define ABS(a) ((a) > 0 ? (a) : (-(a))) #define SIGN(a) ((a) > 0 ? 1 : -1) #define GET_MODE_BUFFER_SIZE 500 #define OPTIONS_ARRAY_SIZE 10 #define BLOCK_SIZE 8 #define TEMP_STRIDE 8 //#define NUM_BLOCKS_AT_ONCE 16 //not used yet #ifdef ARCH_X86 static uint64_t __attribute__((aligned(8))) w05= 0x0005000500050005LL; static uint64_t __attribute__((aligned(8))) w20= 0x0020002000200020LL; static uint64_t __attribute__((aligned(8))) b00= 0x0000000000000000LL; static uint64_t __attribute__((aligned(8))) b01= 0x0101010101010101LL; static uint64_t __attribute__((aligned(8))) b02= 0x0202020202020202LL; static uint64_t __attribute__((aligned(8))) b08= 0x0808080808080808LL; static uint64_t __attribute__((aligned(8))) b80= 0x8080808080808080LL; #endif static int verbose= 0; static const int deringThreshold= 20; static struct PPFilter filters[]= { {"hb", "hdeblock", 1, 1, 3, H_DEBLOCK}, {"vb", "vdeblock", 1, 2, 4, V_DEBLOCK}, /* {"hr", "rkhdeblock", 1, 1, 3, H_RK1_FILTER}, {"vr", "rkvdeblock", 1, 2, 4, V_RK1_FILTER},*/ {"h1", "x1hdeblock", 1, 1, 3, H_X1_FILTER}, {"v1", "x1vdeblock", 1, 2, 4, V_X1_FILTER}, {"dr", "dering", 1, 5, 6, DERING}, {"al", "autolevels", 0, 1, 2, LEVEL_FIX}, {"lb", "linblenddeint", 1, 1, 4, LINEAR_BLEND_DEINT_FILTER}, {"li", "linipoldeint", 1, 1, 4, LINEAR_IPOL_DEINT_FILTER}, {"ci", "cubicipoldeint", 1, 1, 4, CUBIC_IPOL_DEINT_FILTER}, {"md", "mediandeint", 1, 1, 4, MEDIAN_DEINT_FILTER}, {"fd", "ffmpegdeint", 1, 1, 4, FFMPEG_DEINT_FILTER}, {"tn", "tmpnoise", 1, 7, 8, TEMP_NOISE_FILTER}, {"fq", "forcequant", 1, 0, 0, FORCE_QUANT}, {NULL, NULL,0,0,0,0} //End Marker }; static char *replaceTable[]= { "default", "hdeblock:a,vdeblock:a,dering:a,autolevels,tmpnoise:a:150:200:400", "de", "hdeblock:a,vdeblock:a,dering:a,autolevels,tmpnoise:a:150:200:400", "fast", "x1hdeblock:a,x1vdeblock:a,dering:a,autolevels,tmpnoise:a:150:200:400", "fa", "x1hdeblock:a,x1vdeblock:a,dering:a,autolevels,tmpnoise:a:150:200:400", NULL //End Marker }; #ifdef ARCH_X86 static inline void unusedVariableWarningFixer() { if(w05 + w20 + b00 + b01 + b02 + b08 + b80 == 0) b00=0; } #endif #ifdef ARCH_X86 static inline void prefetchnta(void *p) { asm volatile( "prefetchnta (%0)\n\t" : : "r" (p) ); } static inline void prefetcht0(void *p) { asm volatile( "prefetcht0 (%0)\n\t" : : "r" (p) ); } static inline void prefetcht1(void *p) { asm volatile( "prefetcht1 (%0)\n\t" : : "r" (p) ); } static inline void prefetcht2(void *p) { asm volatile( "prefetcht2 (%0)\n\t" : : "r" (p) ); } #endif // The horizontal Functions exist only in C cuz the MMX code is faster with vertical filters and transposing /** * Check if the given 8x8 Block is mostly "flat" */ static inline int isHorizDC(uint8_t src[], int stride, PPContext *c) { int numEq= 0; int y; const int dcOffset= ((c->QP*c->ppMode.baseDcDiff)>>8) + 1; const int dcThreshold= dcOffset*2 + 1; for(y=0; y c->ppMode.flatnessThreshold; } /** * Check if the middle 8x8 Block in the given 8x16 block is flat */ static inline int isVertDC_C(uint8_t src[], int stride, PPContext *c){ int numEq= 0; int y; const int dcOffset= ((c->QP*c->ppMode.baseDcDiff)>>8) + 1; const int dcThreshold= dcOffset*2 + 1; src+= stride*4; // src points to begin of the 8x8 Block for(y=0; y c->ppMode.flatnessThreshold; } static inline int isHorizMinMaxOk(uint8_t src[], int stride, int QP) { if(abs(src[0] - src[7]) > 2*QP) return 0; return 1; } static inline void doHorizDefFilter(uint8_t dst[], int stride, int QP) { int y; for(y=0; y> 6; d*= SIGN(-middleEnergy); if(q>0) { d= d<0 ? 0 : d; d= d>q ? q : d; } else { d= d>0 ? 0 : d; d= d>4; dst[1]= ((dst[1]<<2) + ((first + sums[0] + sums[3])<<1) + sums[5] + 8)>>4; dst[2]= ((dst[2]<<2) + ((first + sums[1] + sums[4])<<1) + sums[6] + 8)>>4; dst[3]= ((dst[3]<<2) + ((sums[2] + sums[5])<<1) + sums[0] + sums[7] + 8)>>4; dst[4]= ((dst[4]<<2) + ((sums[3] + sums[6])<<1) + sums[1] + sums[8] + 8)>>4; dst[5]= ((dst[5]<<2) + ((last + sums[7] + sums[4])<<1) + sums[2] + 8)>>4; dst[6]= (((last + dst[6])<<2) + ((dst[7] + sums[5])<<1) + sums[3] + 8)>>4; dst[7]= ((sums[8]<<2) + ((last + sums[6])<<1) + sums[4] + 8)>>4; dst+= stride; } } /** * Experimental Filter 1 (Horizontal) * will not damage linear gradients * Flat blocks should look like they where passed through the (1,1,2,2,4,2,2,1,1) 9-Tap filter * can only smooth blocks at the expected locations (it cant smooth them if they did move) * MMX2 version does correct clipping C version doesnt * not identical with the vertical one */ static inline void horizX1Filter(uint8_t *src, int stride, int QP) { int y; static uint64_t *lut= NULL; if(lut==NULL) { int i; lut= (uint64_t*)memalign(8, 256*8); for(i=0; i<256; i++) { int v= i < 128 ? 2*i : 2*(i-256); /* //Simulate 112242211 9-Tap filter uint64_t a= (v/16) & 0xFF; uint64_t b= (v/8) & 0xFF; uint64_t c= (v/4) & 0xFF; uint64_t d= (3*v/8) & 0xFF; */ //Simulate piecewise linear interpolation uint64_t a= (v/16) & 0xFF; uint64_t b= (v*3/16) & 0xFF; uint64_t c= (v*5/16) & 0xFF; uint64_t d= (7*v/16) & 0xFF; uint64_t A= (0x100 - a)&0xFF; uint64_t B= (0x100 - b)&0xFF; uint64_t C= (0x100 - c)&0xFF; uint64_t D= (0x100 - c)&0xFF; lut[i] = (a<<56) | (b<<48) | (c<<40) | (d<<32) | (D<<24) | (C<<16) | (B<<8) | (A); //lut[i] = (v<<32) | (v<<24); } } for(y=0; yppMode= *ppMode; //FIXME // useing ifs here as they are faster than function pointers allthough the // difference wouldnt be messureable here but its much better because // someone might exchange the cpu whithout restarting mplayer ;) #ifdef RUNTIME_CPUDETECT #ifdef ARCH_X86 // ordered per speed fasterst first if(c->cpuCaps & PP_CPU_CAPS_MMX2) postProcess_MMX2(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c); else if(c->cpuCaps & PP_CPU_CAPS_3DNOW) postProcess_3DNow(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c); else if(c->cpuCaps & PP_CPU_CAPS_MMX) postProcess_MMX(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c); else postProcess_C(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c); #else postProcess_C(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c); #endif #else //RUNTIME_CPUDETECT #ifdef HAVE_MMX2 postProcess_MMX2(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c); #elif defined (HAVE_3DNOW) postProcess_3DNow(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c); #elif defined (HAVE_MMX) postProcess_MMX(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c); #else postProcess_C(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c); #endif #endif //!RUNTIME_CPUDETECT } //static void postProcess(uint8_t src[], int srcStride, uint8_t dst[], int dstStride, int width, int height, // QP_STORE_T QPs[], int QPStride, int isColor, struct PPMode *ppMode); /* -pp Command line Help */ char *pp_help= "[: