Skip to content
Snippets Groups Projects
postprocess.c 54.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • 		"pminsw %%mm0, %%mm4				\n\t"
    		"pminsw %%mm1, %%mm5				\n\t"
    #else
    		"movq %%mm4, %%mm2				\n\t"
    		"psubusw %%mm0, %%mm2				\n\t"
    		"psubw %%mm2, %%mm4				\n\t"
    		"movq %%mm5, %%mm2				\n\t"
    		"psubusw %%mm1, %%mm2				\n\t"
    		"psubw %%mm2, %%mm5				\n\t"
    #endif
    		"pxor %%mm6, %%mm4				\n\t"
    		"pxor %%mm7, %%mm5				\n\t"
    		"psubw %%mm6, %%mm4				\n\t"
    		"psubw %%mm7, %%mm5				\n\t"
    		"packsswb %%mm5, %%mm4				\n\t"
    		"movq (%%eax, %1, 2), %%mm0			\n\t"
    		"paddb   %%mm4, %%mm0				\n\t"
    		"movq %%mm0, (%%eax, %1, 2) 			\n\t"
    		"movq (%0, %1, 4), %%mm0			\n\t"
    		"psubb %%mm4, %%mm0				\n\t"
    //		"pxor %%mm0, %%mm0 \n\t"
    		"movq %%mm0, (%0, %1, 4) 			\n\t"
    
    		:
    		: "r" (src), "r" (stride), "r" (QP)
    		: "%eax", "%ebx"
    	);
    #else
    	const int l1= stride;
    	const int l2= stride + l1;
    	const int l3= stride + l2;
    	const int l4= stride + l3;
    	const int l5= stride + l4;
    	const int l6= stride + l5;
    	const int l7= stride + l6;
    	const int l8= stride + l7;
    //	const int l9= stride + l8;
    
    	int x;
    	for(x=0; x<BLOCK_SIZE; x++)
    
    	{
    		const int middleEnergy= 5*(src[l5] - src[l4]) + 2*(src[l3] - src[l6]);
    		if(ABS(middleEnergy) < 8*QP)
    		{
    			const int q=(src[l4] - src[l5])/2;
    			const int leftEnergy=  5*(src[l3] - src[l2]) + 2*(src[l1] - src[l4]);
    			const int rightEnergy= 5*(src[l7] - src[l6]) + 2*(src[l5] - src[l8]);
    
    			int d= ABS(middleEnergy) - MIN( ABS(leftEnergy), ABS(rightEnergy) );
    			d= MAX(d, 0);
    
    			d= (5*d + 32) >> 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<q ? q : d;
    			}
    
            		src[l4]-= d;
    	        	src[l5]+= d;
    		}
    		src++;
    	}
    #endif
    }
    
    //FIXME?  |255-0| = 1
    /**
     * Check if the given 8x8 Block is mostly "flat" and copy the unaliged data into tempBlock.
     */
    
    static inline int isHorizDCAndCopy2Temp(uint8_t src[], int stride)
    
    {
    //	src++;
    	int numEq= 0;
    #ifdef HAVE_MMX
    asm volatile (
    //		"int $3 \n\t"
    		"pushl %1\n\t"
    		"movq b7E, %%mm7				\n\t" // mm7 = 0x7F
    		"movq b7C, %%mm6				\n\t" // mm6 = 0x7D
    		"leal tempBlock, %%eax				\n\t"
    		"pxor %%mm0, %%mm0				\n\t"
    
    #define HDC_CHECK_AND_CPY(i) \
    		"movq -4(%1), %%mm2				\n\t"\
    		"psrlq $32, %%mm2				\n\t"\
    		"punpckldq 4(%1), %%mm2				\n\t" /* (%1) */\
    		"movq %%mm2, %%mm1				\n\t"\
    		"psrlq $8, %%mm2				\n\t"\
    		"psubb %%mm1, %%mm2				\n\t"\
    		"paddb %%mm7, %%mm2				\n\t"\
    		"pcmpgtb %%mm6, %%mm2				\n\t"\
    		"paddb %%mm2, %%mm0				\n\t"\
    		"movq %%mm1," #i "(%%eax)			\n\t"
    
    		HDC_CHECK_AND_CPY(0)
    		"addl %2, %1					\n\t"
    		HDC_CHECK_AND_CPY(8)
    		"addl %2, %1					\n\t"
    		HDC_CHECK_AND_CPY(16)
    		"addl %2, %1					\n\t"
    		HDC_CHECK_AND_CPY(24)
    		"addl %2, %1					\n\t"
    		HDC_CHECK_AND_CPY(32)
    		"addl %2, %1					\n\t"
    		HDC_CHECK_AND_CPY(40)
    		"addl %2, %1					\n\t"
    		HDC_CHECK_AND_CPY(48)
    		"addl %2, %1					\n\t"
    		HDC_CHECK_AND_CPY(56)
    
    		"psllq $8, %%mm0				\n\t" // remove dummy value
    		"movq %%mm0, %%mm1				\n\t"
    		"psrlw $8, %%mm0				\n\t"
    		"paddb %%mm1, %%mm0				\n\t"
    		"movq %%mm0, %%mm1				\n\t"
    		"psrlq $16, %%mm0				\n\t"
    		"paddb %%mm1, %%mm0				\n\t"
    		"movq %%mm0, %%mm1				\n\t"
    		"psrlq $32, %%mm0				\n\t"
    		"paddb %%mm1, %%mm0				\n\t"
    		"popl %1\n\t"
    		"movd %%mm0, %0					\n\t"
    		: "=r" (numEq)
    		: "r" (src), "r" (stride)
    		: "%eax"
    		);
    //	printf("%d\n", numEq);
    	numEq= (256 - (numEq & 0xFF)) &0xFF;
    #else
    
    	int y;
    	for(y=0; y<BLOCK_SIZE; y++)
    
    	{
    		if(((src[0] - src[1] + 1) & 0xFFFF) < 3) numEq++;
    		if(((src[1] - src[2] + 1) & 0xFFFF) < 3) numEq++;
    		if(((src[2] - src[3] + 1) & 0xFFFF) < 3) numEq++;
    		if(((src[3] - src[4] + 1) & 0xFFFF) < 3) numEq++;
    		if(((src[4] - src[5] + 1) & 0xFFFF) < 3) numEq++;
    		if(((src[5] - src[6] + 1) & 0xFFFF) < 3) numEq++;
    		if(((src[6] - src[7] + 1) & 0xFFFF) < 3) numEq++;
    		tempBlock[0 + y*TEMP_STRIDE] = src[0];
    		tempBlock[1 + y*TEMP_STRIDE] = src[1];
    		tempBlock[2 + y*TEMP_STRIDE] = src[2];
    		tempBlock[3 + y*TEMP_STRIDE] = src[3];
    		tempBlock[4 + y*TEMP_STRIDE] = src[4];
    		tempBlock[5 + y*TEMP_STRIDE] = src[5];
    		tempBlock[6 + y*TEMP_STRIDE] = src[6];
    		tempBlock[7 + y*TEMP_STRIDE] = src[7];
    		src+= stride;
    	}
    #endif
    /*	if(abs(numEq - asmEq) > 0)
    	{
    //		printf("\nasm:%d  c:%d\n", asmEq, numEq);
    		for(int y=0; y<8; y++)
    		{
    			for(int x=0; x<8; x++)
    			{
    				printf("%d ", src[x + y*stride]);
    			}
    			printf("\n");
    		}
    	}
    */
    //	printf("%d\n", numEq);
    	return numEq > hFlatnessThreshold;
    }
    
    
    static inline int isHorizMinMaxOk(uint8_t src[], int stride, int QP)
    
    {
    #ifdef MMX_FIXME
    FIXME
    	int isOk;
    	asm volatile(
    //		"int $3 \n\t"
    		"movq (%1, %2), %%mm0				\n\t"
    		"movq (%1, %2, 8), %%mm1			\n\t"
    		"movq %%mm0, %%mm2				\n\t"
    		"psubusb %%mm1, %%mm0				\n\t"
    		"psubusb %%mm2, %%mm1				\n\t"
    		"por %%mm1, %%mm0				\n\t" // ABS Diff
    
    		"movq pQPb, %%mm7				\n\t" // QP,..., QP
    		"paddusb %%mm7, %%mm7				\n\t" // 2QP ... 2QP
    		"psubusb %%mm7, %%mm0				\n\t" // Diff <= 2QP -> 0
    		"pcmpeqd b00, %%mm0				\n\t"
    		"psrlq $16, %%mm0				\n\t"
    		"pcmpeqd bFF, %%mm0				\n\t"
    //		"movd %%mm0, (%1, %2, 4)\n\t"
    		"movd %%mm0, %0					\n\t"
    		: "=r" (isOk)
    		: "r" (src), "r" (stride)
    		);
    	return isOk;
    #else
    
    	if(abs(src[0] - src[7]) > 2*QP) return 0;
    
    #endif
    }
    
    static inline void doHorizDefFilterAndCopyBack(uint8_t dst[], int stride, int QP)
    {
    
    #ifdef HAVE_MMX
    
    	asm volatile(
    		"pushl %0					\n\t"
    		"pxor %%mm7, %%mm7				\n\t"
    		"movq bm00001000, %%mm6				\n\t"
    		"movd %2, %%mm5					\n\t" // QP
    		"movq %%mm5, %%mm4				\n\t"
    		"paddusb %%mm5, %%mm5				\n\t" // 2QP
    		"paddusb %%mm5, %%mm4				\n\t" // 3QP
    		"psllq $24, %%mm4				\n\t"
    		"pxor %%mm5, %%mm5				\n\t" // 0
    		"psubb %%mm4, %%mm5				\n\t" // -QP
    		"leal tempBlock, %%eax				\n\t"
    
    //FIXME? "unroll by 2" and mix
    
    #ifdef HAVE_MMX2
    #define HDF(i)	\
    		"movq " #i "(%%eax), %%mm0			\n\t"\
    		"movq %%mm0, %%mm1				\n\t"\
    		"movq %%mm0, %%mm2				\n\t"\
    		"psrlq $8, %%mm1				\n\t"\
    		"psubusb %%mm1, %%mm2				\n\t"\
    		"psubusb %%mm0, %%mm1				\n\t"\
    		"por %%mm2, %%mm1				\n\t" /* px = |px - p(x+1)| */\
    		"pcmpeqb %%mm7, %%mm2				\n\t" /* px = sgn[px - p(x+1)] */\
    		"pshufw $0x00, %%mm1, %%mm3			\n\t" /* p5 = |p1 - p2| */\
    		"pminub %%mm1, %%mm3				\n\t" /* p5 = min(|p2-p1|, |p6-p5|)*/\
    		"psrlq $16, %%mm3				\n\t" /* p3 = min(|p2-p1|, |p6-p5|)*/\
    		"psubusb %%mm3, %%mm1			\n\t" /* |p3-p4|-min(|p1-p2|,|p5-p6|) */\
    		"paddb %%mm5, %%mm1				\n\t"\
    		"psubusb %%mm5, %%mm1				\n\t"\
    		"psrlw $2, %%mm1				\n\t"\
    		"pxor %%mm2, %%mm1				\n\t"\
    		"psubb %%mm2, %%mm1				\n\t"\
    		"pand %%mm6, %%mm1				\n\t"\
    		"psubb %%mm1, %%mm0				\n\t"\
    		"psllq $8, %%mm1				\n\t"\
    		"paddb %%mm1, %%mm0				\n\t"\
    		"movd %%mm0, (%0)				\n\t"\
    		"psrlq $32, %%mm0				\n\t"\
    		"movd %%mm0, 4(%0)				\n\t"
    #else
    #define HDF(i)\
    		"movq " #i "(%%eax), %%mm0			\n\t"\
    
    		"movq %%mm0, %%mm1				\n\t"\
    		"movq %%mm0, %%mm2				\n\t"\
    		"psrlq $8, %%mm1				\n\t"\
    		"psubusb %%mm1, %%mm2				\n\t"\
    		"psubusb %%mm0, %%mm1				\n\t"\
    
    		"por %%mm2, %%mm1				\n\t" /* px = |px - p(x+1)| */\
    		"pcmpeqb %%mm7, %%mm2				\n\t" /* px = sgn[px - p(x+1)] */\
    		"movq %%mm1, %%mm3				\n\t"\
    		"psllq $32, %%mm3				\n\t"\
    		"movq %%mm3, %%mm4				\n\t"\
    		"psubusb %%mm1, %%mm4				\n\t"\
    		"psubb %%mm4, %%mm3				\n\t"\
    		"psrlq $16, %%mm3				\n\t" /* p3 = min(|p2-p1|, |p6-p5|)*/\
    
    		"psubusb %%mm3, %%mm1			\n\t" /* |p3-p4|-min(|p1-p2|,|p5,6|) */\
    		"paddb %%mm5, %%mm1				\n\t"\
    		"psubusb %%mm5, %%mm1				\n\t"\
    		"psrlw $2, %%mm1				\n\t"\
    		"pxor %%mm2, %%mm1				\n\t"\
    		"psubb %%mm2, %%mm1				\n\t"\
    		"pand %%mm6, %%mm1				\n\t"\
    		"psubb %%mm1, %%mm0				\n\t"\
    		"psllq $8, %%mm1				\n\t"\
    		"paddb %%mm1, %%mm0				\n\t"\
    		"movd %%mm0, (%0)				\n\t"\
    		"psrlq $32, %%mm0				\n\t"\
    		"movd %%mm0, 4(%0)				\n\t"
    
    		HDF(0)
    		"addl %1, %0					\n\t"
    		HDF(8)
    		"addl %1, %0					\n\t"
    		HDF(16)
    		"addl %1, %0					\n\t"
    		HDF(24)
    		"addl %1, %0					\n\t"
    		HDF(32)
    		"addl %1, %0					\n\t"
    		HDF(40)
    		"addl %1, %0					\n\t"
    		HDF(48)
    		"addl %1, %0					\n\t"
    		HDF(56)
    		"popl %0					\n\t"
    		:
    		: "r" (dst), "r" (stride), "r" (QP)
    		: "%eax"
    	);
    #else
    	uint8_t *src= tempBlock;
    
    
    	int y;
    	for(y=0; y<BLOCK_SIZE; y++)
    
    	{
    		dst[0] = src[0];
    		dst[1] = src[1];
    		dst[2] = src[2];
    		dst[3] = src[3];
    		dst[4] = src[4];
    		dst[5] = src[5];
    		dst[6] = src[6];
    		dst[7] = src[7];
    
    		const int middleEnergy= 5*(src[4] - src[5]) + 2*(src[2] - src[5]);
    		if(ABS(middleEnergy) < 8*QP)
    		{
    			const int q=(src[3] - src[4])/2;
    			const int leftEnergy=  5*(src[2] - src[1]) + 2*(src[0] - src[3]);
    			const int rightEnergy= 5*(src[6] - src[5]) + 2*(src[4] - src[7]);
    
    			int d= ABS(middleEnergy) - MIN( ABS(leftEnergy), ABS(rightEnergy) );
    			d= MAX(d, 0);
    
    			d= (5*d + 32) >> 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<q ? q : d;
    			}
    
            		dst[3]-= d;
    	        	dst[4]+= d;
    		}
    		dst+= stride;
    		src+= TEMP_STRIDE;
    	}
    #endif
    }
    
    /**
     * Do a horizontal low pass filter on the 8x8 block
     * useing the 9-Tap Filter (1,1,2,2,4,2,2,1,1)/16 (C version)
    
     * useing approximately the 7-Tap Filter (1,2,3,4,3,2,1)/16 (MMX2/3DNOW version)
    
     */
    static inline void doHorizLowPassAndCopyBack(uint8_t dst[], int stride, int QP)
    {
    //return;
    
    #if defined (HAVE_MMX2) || defined (HAVE_3DNOW)
    
    	asm volatile(	//"movv %0 %1 %2\n\t"
    		"pushl %0\n\t"
    		"pxor %%mm7, %%mm7					\n\t"
    		"leal tempBlock, %%eax					\n\t"
    
    #define HLP1	"movq (%0), %%mm0					\n\t"\
    		"movq %%mm0, %%mm1					\n\t"\
    		"psllq $8, %%mm0					\n\t"\
    
    		PAVGB(%%mm1, %%mm0)\
    
    		"psrlw $8, %%mm0					\n\t"\
    		"pxor %%mm1, %%mm1					\n\t"\
    		"packuswb %%mm1, %%mm0					\n\t"\
    		"movq %%mm0, %%mm1					\n\t"\
    		"movq %%mm0, %%mm2					\n\t"\
    		"psllq $32, %%mm0					\n\t"\
    		"paddb %%mm0, %%mm1					\n\t"\
    		"psllq $16, %%mm2					\n\t"\
    
    		PAVGB(%%mm2, %%mm0)\
    
    		"movq %%mm0, %%mm3					\n\t"\
    		"pand bm11001100, %%mm0					\n\t"\
    		"paddusb %%mm0, %%mm3					\n\t"\
    		"psrlq $8, %%mm3					\n\t"\
    
    		PAVGB(%%mm1, %%mm4)\
    		PAVGB(%%mm3, %%mm2)\
    
    		"psrlq $16, %%mm2					\n\t"\
    		"punpcklbw %%mm2, %%mm2					\n\t"\
    		"movq %%mm2, (%0)					\n\t"\
    
    #define HLP2	"movq (%0), %%mm0					\n\t"\
    		"movq %%mm0, %%mm1					\n\t"\
    		"psllq $8, %%mm0					\n\t"\
    
    		PAVGB(%%mm1, %%mm0)\
    
    		"psrlw $8, %%mm0					\n\t"\
    		"pxor %%mm1, %%mm1					\n\t"\
    		"packuswb %%mm1, %%mm0					\n\t"\
    		"movq %%mm0, %%mm2					\n\t"\
    		"psllq $32, %%mm0					\n\t"\
    		"psllq $16, %%mm2					\n\t"\
    
    		PAVGB(%%mm2, %%mm0)\
    
    		"movq %%mm0, %%mm3					\n\t"\
    		"pand bm11001100, %%mm0					\n\t"\
    		"paddusb %%mm0, %%mm3					\n\t"\
    		"psrlq $8, %%mm3					\n\t"\
    
    		PAVGB(%%mm3, %%mm2)\
    
    		"psrlq $16, %%mm2					\n\t"\
    		"punpcklbw %%mm2, %%mm2					\n\t"\
    		"movq %%mm2, (%0)					\n\t"\
    
    // approximately a 7-Tap Filter with Vector (1,2,3,4,3,2,1)/16
    /*
     31
     121
      121
       121
        121
         121
          121
           13
    Implemented	Exact 7-Tap
     9421		A321
     36421		64321
     334321		=
     1234321	=
      1234321	=
       123433	=
        12463	  12346
         1249	   123A
    
    */
    
    #ifdef HAVE_MMX2
    
    #define HLP3(i)	"movq " #i "(%%eax), %%mm0				\n\t"\
    		"movq %%mm0, %%mm1					\n\t"\
    		"movq %%mm0, %%mm2					\n\t"\
    		"movq %%mm0, %%mm3					\n\t"\
    		"movq %%mm0, %%mm4					\n\t"\
    		"psllq $8, %%mm1					\n\t"\
    		"psrlq $8, %%mm2					\n\t"\
    		"pand bm00000001, %%mm3					\n\t"\
    		"pand bm10000000, %%mm4					\n\t"\
    		"por %%mm3, %%mm1					\n\t"\
    		"por %%mm4, %%mm2					\n\t"\
    
    		PAVGB(%%mm2, %%mm1)\
    		PAVGB(%%mm1, %%mm0)\
    
    \
    		"pshufw $0xF9, %%mm0, %%mm3				\n\t"\
    		"pshufw $0x90, %%mm0, %%mm4				\n\t"\
    
    		PAVGB(%%mm3, %%mm4)\
    		PAVGB(%%mm4, %%mm0)\
    
    		"movd %%mm0, (%0)					\n\t"\
    		"psrlq $32, %%mm0					\n\t"\
    
    		"movd %%mm0, 4(%0)					\n\t"
    #else
    #define HLP3(i)	"movq " #i "(%%eax), %%mm0				\n\t"\
    		"movq %%mm0, %%mm1					\n\t"\
    		"movq %%mm0, %%mm2					\n\t"\
    		"movq %%mm0, %%mm3					\n\t"\
    		"movq %%mm0, %%mm4					\n\t"\
    		"psllq $8, %%mm1					\n\t"\
    		"psrlq $8, %%mm2					\n\t"\
    		"pand bm00000001, %%mm3					\n\t"\
    		"pand bm10000000, %%mm4					\n\t"\
    		"por %%mm3, %%mm1					\n\t"\
    		"por %%mm4, %%mm2					\n\t"\
    		PAVGB(%%mm2, %%mm1)\
    		PAVGB(%%mm1, %%mm0)\
    \
    		"movq %%mm0, %%mm3					\n\t"\
    		"movq %%mm0, %%mm4					\n\t"\
    		"movq %%mm0, %%mm5					\n\t"\
    		"psrlq $16, %%mm3					\n\t"\
    		"psllq $16, %%mm4					\n\t"\
    		"pand bm11000000, %%mm5					\n\t"\
    		"por %%mm5, %%mm3					\n\t"\
    		"movq %%mm0, %%mm5					\n\t"\
    		"pand bm00000011, %%mm5					\n\t"\
    		"por %%mm5, %%mm4					\n\t"\
    		PAVGB(%%mm3, %%mm4)\
    		PAVGB(%%mm4, %%mm0)\
    		"movd %%mm0, (%0)					\n\t"\
    		"psrlq $32, %%mm0					\n\t"\
    		"movd %%mm0, 4(%0)					\n\t"
    #endif
    
    
    #define HLP(i) HLP3(i)
    
    		HLP(0)
    		"addl %1, %0						\n\t"
    		HLP(8)
    		"addl %1, %0						\n\t"
    		HLP(16)
    		"addl %1, %0						\n\t"
    		HLP(24)
    		"addl %1, %0						\n\t"
    		HLP(32)
    		"addl %1, %0						\n\t"
    		HLP(40)
    		"addl %1, %0						\n\t"
    		HLP(48)
    		"addl %1, %0						\n\t"
    		HLP(56)
    
    		"popl %0\n\t"
    		:
    		: "r" (dst), "r" (stride)
    		: "%eax", "%ebx"
    	);
    
    #else
    	uint8_t *temp= tempBlock;
    
    	int y;
    	for(y=0; y<BLOCK_SIZE; y++)
    
    	{
    		const int first= ABS(dst[-1] - dst[0]) < QP ? dst[-1] : dst[0];
    		const int last= ABS(dst[8] - dst[7]) < QP ? dst[8] : dst[7];
    
    		int sums[9];
    		sums[0] = first + temp[0];
    		sums[1] = temp[0] + temp[1];
    		sums[2] = temp[1] + temp[2];
    		sums[3] = temp[2] + temp[3];
    		sums[4] = temp[3] + temp[4];
    		sums[5] = temp[4] + temp[5];
    		sums[6] = temp[5] + temp[6];
    		sums[7] = temp[6] + temp[7];
    		sums[8] = temp[7] + last;
    
    		dst[0]= ((sums[0]<<2) + ((first + sums[2])<<1) + sums[4] + 8)>>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;
    		temp+= TEMP_STRIDE;
    	}
    #endif
    }
    
    
    static inline void dering(uint8_t src[], int stride, int QP)
    {
    //FIXME
    
    #ifdef HAVE_MMX2X
    	asm volatile(
    		"leal (%0, %1), %%eax				\n\t"
    		"leal (%%eax, %1, 4), %%ebx			\n\t"
    //	0	1	2	3	4	5	6	7	8	9
    //	%0	eax	eax+%1	eax+2%1	%0+4%1	ebx	ebx+%1	ebx+2%1	%0+8%1	ebx+4%1
    
    		"pcmpeq %%mm6, %%mm6				\n\t"
    		"pxor %%mm7, %%mm7				\n\t"
    
    #define FIND_MIN_MAX(addr)\
    		"movq (" #addr "), %%mm0,			\n\t"\
    		"pminub %%mm0, %%mm6				\n\t"\
    		"pmaxub %%mm0, %%mm7				\n\t"
    
    FIND_MIN_MAX(%0)
    FIND_MIN_MAX(%%eax)
    FIND_MIN_MAX(%%eax, %1)
    FIND_MIN_MAX(%%eax, %1, 2)
    FIND_MIN_MAX(%0, %1, 4)
    FIND_MIN_MAX(%%ebx)
    FIND_MIN_MAX(%%ebx, %1)
    FIND_MIN_MAX(%%ebx, %1, 2)
    FIND_MIN_MAX(%0, %1, 8)
    FIND_MIN_MAX(%%ebx, %1, 2)
    
    		"movq %%mm6, %%mm4				\n\t"
    		"psrlq $32, %%mm6				\n\t"
    		"pminub %%mm4, %%mm6				\n\t"
    		"movq %%mm6, %%mm4				\n\t"
    		"psrlq $16, %%mm6				\n\t"
    		"pminub %%mm4, %%mm6				\n\t"
    		"movq %%mm6, %%mm4				\n\t"
    		"psrlq $8, %%mm6				\n\t"
    		"pminub %%mm4, %%mm6				\n\t" // min of pixels
    
    		"movq %%mm7, %%mm4				\n\t"
    		"psrlq $32, %%mm7				\n\t"
    		"pmaxub %%mm4, %%mm7				\n\t"
    		"movq %%mm7, %%mm4				\n\t"
    		"psrlq $16, %%mm7				\n\t"
    		"pmaxub %%mm4, %%mm7				\n\t"
    		"movq %%mm7, %%mm4				\n\t"
    		"psrlq $8, %%mm7				\n\t"
    		"pmaxub %%mm4, %%mm7				\n\t" // max of pixels
    
    		PAVGB(%%mm6, %%mm7)				      // (max + min)/2
    
    
    
    		: : "r" (src), "r" (stride), "r" (QP)
    		: "%eax", "%ebx"
    	);
    #else
    
    //FIXME
    #endif
    }
    
    
     * the mode value is interpreted as a quality value if its negative, its range is then (-1 ... -63)
     * -63 is best quality -1 is worst
    
    //extern "C"{
    
    void  postprocess(unsigned char * src[], int src_stride,
                     unsigned char * dst[], int dst_stride,
                     int horizontal_size,   int vertical_size,
                     QP_STORE_T *QP_store,  int QP_stride,
    					  int mode)
    {
    
    
    	if(mode<0) mode= getModeForQuality(-mode);
    
    
    /*
    	long long T= rdtsc();
    	for(int y=vertical_size-1; y>=0 ; y--)
    		memcpy(dst[0] + y*src_stride, src[0] + y*src_stride,src_stride);
    //	memcpy(dst[0], src[0],src_stride*vertical_size);
    	printf("%4dk\r", (rdtsc()-T)/1000);
    
    	return;
    */
    /*
    	long long T= rdtsc();
    	while( (rdtsc() - T)/1000 < 4000);
    
    	return;
    */
    
    	postProcess(src[0], src_stride, dst[0], dst_stride,
    
    		horizontal_size, vertical_size, QP_store, QP_stride, 0, mode);
    
    
    	horizontal_size >>= 1;
    	vertical_size   >>= 1;
    	src_stride      >>= 1;
    	dst_stride      >>= 1;
    
    	if(1)
    	{
    
    		postProcess(src[1], src_stride, dst[1], dst_stride,
    
    			horizontal_size, vertical_size, QP_store, QP_stride, 1, mode >>4);
    
    		postProcess(src[2], src_stride, dst[2], dst_stride,
    
    			horizontal_size, vertical_size, QP_store, QP_stride, 1, mode >>4);
    
    	}
    	else
    	{
    		memcpy(dst[1], src[1], src_stride*horizontal_size);
    		memcpy(dst[2], src[2], src_stride*horizontal_size);
    	}
    }
    
    /**
     * gets the mode flags for a given quality (larger values mean slower but better postprocessing)
     * 0 <= quality < 64
     */
    int getModeForQuality(int quality){
    	int modes[6]= {
    		LUM_V_DEBLOCK,
    		LUM_V_DEBLOCK | LUM_H_DEBLOCK,
    		LUM_V_DEBLOCK | LUM_H_DEBLOCK | CHROM_V_DEBLOCK,
    		LUM_V_DEBLOCK | LUM_H_DEBLOCK | CHROM_V_DEBLOCK | CHROM_H_DEBLOCK,
    		LUM_V_DEBLOCK | LUM_H_DEBLOCK | CHROM_V_DEBLOCK | CHROM_H_DEBLOCK | LUM_DERING,
    		LUM_V_DEBLOCK | LUM_H_DEBLOCK | CHROM_V_DEBLOCK | CHROM_H_DEBLOCK | LUM_DERING | CHROM_DERING
    		};
    
    	return modes[ (quality*6) >>6 ];
    
    //} // extern "C"
    
    /**
     * Copies a block from src to dst and fixes the blacklevel
    
     * numLines must be a multiple of 4
     * levelFix == 0 -> dont touch the brighness & contrast
    
    static inline void blockCopy(uint8_t dst[], int dstStride, uint8_t src[], int srcStride,
    	int numLines, int levelFix)
    
    #ifdef HAVE_MMX
    					asm volatile(
    
    						"movl %4, %%eax \n\t"
    						"movl %%eax, temp0\n\t"
    
    						"pushl %0 \n\t"
    						"pushl %1 \n\t"
    						"leal (%2,%2), %%eax	\n\t"
    						"leal (%3,%3), %%ebx	\n\t"
    						"movq packedYOffset, %%mm2	\n\t"
    						"movq packedYScale, %%mm3	\n\t"
    
    #define SCALED_CPY					\
    						"movq (%0), %%mm0	\n\t"\
    						"movq (%0,%2), %%mm1	\n\t"\
    						"psubusb %%mm2, %%mm0	\n\t"\
    						"psubusb %%mm2, %%mm1	\n\t"\
    						"pxor %%mm4, %%mm4	\n\t"\
    						"pxor %%mm5, %%mm5	\n\t"\
    						"punpcklbw %%mm0, %%mm4 \n\t"\
    						"punpckhbw %%mm0, %%mm5 \n\t"\
    						"pmulhuw %%mm3, %%mm4	\n\t"\
    						"pmulhuw %%mm3, %%mm5	\n\t"\
    						"packuswb %%mm5, %%mm4	\n\t"\
    						"movq %%mm4, (%1)	\n\t"\
    						"pxor %%mm4, %%mm4	\n\t"\
    						"pxor %%mm5, %%mm5	\n\t"\
    						"punpcklbw %%mm1, %%mm4 \n\t"\
    						"punpckhbw %%mm1, %%mm5 \n\t"\
    						"pmulhuw %%mm3, %%mm4	\n\t"\
    						"pmulhuw %%mm3, %%mm5	\n\t"\
    						"packuswb %%mm5, %%mm4	\n\t"\
    						"movq %%mm4, (%1, %3)	\n\t"\
    
    
    						"addl %%eax, %0		\n\t"
    						"addl %%ebx, %1		\n\t"
    
    						"addl %%eax, %0		\n\t"
    						"addl %%ebx, %1		\n\t"
    
    						"decl temp0		\n\t"
    						"jnz 1b			\n\t"
    
    						"popl %1 \n\t"
    						"popl %0 \n\t"
    						: : "r" (src),
    						"r" (dst),
    						"r" (srcStride),
    						"r" (dstStride),
    						"m" (numLines>>2)
    						: "%eax", "%ebx"
    					);
    #else
    				for(i=0; i<numLines; i++)
    					memcpy(	&(dst[dstStride*i]),
    						&(src[srcStride*i]), BLOCK_SIZE);
    #endif
    	}
    	else
    	{
    #ifdef HAVE_MMX
    					asm volatile(
    						"movl %4, %%eax \n\t"
    						"movl %%eax, temp0\n\t"
    						"pushl %0 \n\t"
    						"pushl %1 \n\t"
    						"leal (%2,%2), %%eax	\n\t"
    						"leal (%3,%3), %%ebx	\n\t"
    						"movq packedYOffset, %%mm2	\n\t"
    						"movq packedYScale, %%mm3	\n\t"
    
    #define SIMPLE_CPY					\
    						"movq (%0), %%mm0	\n\t"\
    						"movq (%0,%2), %%mm1	\n\t"\
    						"movq %%mm0, (%1)	\n\t"\
    						"movq %%mm1, (%1, %3)	\n\t"\
    
    						"1:			\n\t"
    SIMPLE_CPY
    						"addl %%eax, %0		\n\t"
    						"addl %%ebx, %1		\n\t"
    SIMPLE_CPY
    
    						"addl %%eax, %0		\n\t"
    						"addl %%ebx, %1		\n\t"
    
    						"popl %1 \n\t"
    						"popl %0 \n\t"
    						: : "r" (src),
    						"r" (dst),
    						"r" (srcStride),
    
    						"r" (dstStride),
    						"m" (numLines>>2)
    
    					memcpy(	&(dst[dstStride*i]),
    						&(src[srcStride*i]), BLOCK_SIZE);
    #endif
    
    }
    
    
    /**
     * Filters array of bytes (Y or U or V values)
     */
    void postProcess(uint8_t src[], int srcStride, uint8_t dst[], int dstStride, int width, int height,
    
    	QP_STORE_T QPs[], int QPStride, int isColor, int mode)
    
    	int x,y;
    	/* we need 64bit here otherwise well going to have a problem
    	   after watching a black picture for 5 hours*/
    	static uint64_t *yHistogram= NULL;
    	int black=0, white=255; // blackest black and whitest white in the picture
    
    
    #ifdef TIMEING
    	long long T0, T1, memcpyTime=0, vertTime=0, horizTime=0, sumTime, diffTime=0;
    	sumTime= rdtsc();
    #endif
    
    	if(!yHistogram)
    	{
    
    		int i;
    		yHistogram= (uint64_t*)malloc(8*256);
    		for(i=0; i<256; i++) yHistogram[i]= width*height/64*15/256;
    
    		int i;
    		static int framenum= -1;
    		uint64_t maxClipped;
    		uint64_t clipped;
    		double scale;
    
    		framenum++;
    		if(framenum == 1) yHistogram[0]= width*height/64*15/256;
    
    		for(i=0; i<256; i++)
    		{
    
    //			printf("%d ", yHistogram[i]);
    		}
    //		printf("\n\n");
    
    		/* we allways get a completly black picture first */
    
    		maxClipped= (uint64_t)(sum * maxClippedThreshold);
    
    		for(black=255; black>0; black--)
    		{
    			if(clipped < maxClipped) break;
    			clipped-= yHistogram[black];
    		}
    
    		clipped= sum;
    		for(white=0; white<256; white++)
    		{
    			if(clipped < maxClipped) break;
    			clipped-= yHistogram[white];
    		}
    
    		// we cant handle negative correctures
    		packedYOffset= MAX(black - minAllowedY, 0);
    		packedYOffset|= packedYOffset<<32;
    		packedYOffset|= packedYOffset<<16;
    		packedYOffset|= packedYOffset<<8;
    
    
    		scale= (double)(maxAllowedY - minAllowedY) / (double)(white-black);
    
    		packedYScale= (uint16_t)(scale*256.0 + 0.5);
    
    		packedYScale|= packedYScale<<32;
    		packedYScale|= packedYScale<<16;
    	}
    	else
    	{
    		packedYScale= 0x0100010001000100LL;
    		packedYOffset= 0;
    	}
    
    
    	for(x=0; x<width; x+=BLOCK_SIZE)
    		blockCopy(dst + x, dstStride, src + x, srcStride, 8, mode & LEVEL_FIX);
    
    	for(y=0; y<height; y+=BLOCK_SIZE)
    
    	{
    		//1% speedup if these are here instead of the inner loop
    		uint8_t *srcBlock= &(src[y*srcStride]);
    		uint8_t *dstBlock= &(dst[y*dstStride]);
    		uint8_t *vertSrcBlock= &(srcBlock[srcStride*3]); // Blocks are 10x8 -> *3 to start
    		uint8_t *vertBlock= &(dstBlock[dstStride*3]);
    
    		// finish 1 block before the next otherwise well might have a problem
    		// with the L1 Cache of the P4 ... or only a few blocks at a time or soemthing
    
    		for(x=0; x<width; x+=BLOCK_SIZE)
    
    			int QP= isColor ?
    				QPs[(y>>3)*QPStride + (x>>3)]:
    				(QPs[(y>>4)*QPStride + (x>>4)] * (packedYScale &0xFFFF))>>8;
    #ifdef HAVE_MMX
    		asm volatile(
    			"movd %0, %%mm7					\n\t"
    			"packuswb %%mm7, %%mm7				\n\t" // 0, 0, 0, QP, 0, 0, 0, QP
    			"packuswb %%mm7, %%mm7				\n\t" // 0,QP, 0, QP, 0,QP, 0, QP
    			"packuswb %%mm7, %%mm7				\n\t" // QP,..., QP
    			"movq %%mm7, pQPb				\n\t"
    			: : "r" (QP)
    		);
    #endif
    
    
    			if(y + 12 < height)
    			{
    #ifdef MORE_TIMEING
    				T0= rdtsc();
    #endif
    
    
    #ifdef HAVE_MMX2
    
    				prefetchnta(vertSrcBlock + (((x>>3)&3) + 2)*srcStride + 32);
    				prefetchnta(vertSrcBlock + (((x>>3)&3) + 6)*srcStride + 32);
    				prefetcht0(vertBlock + (((x>>3)&3) + 2)*dstStride + 32);
    				prefetcht0(vertBlock + (((x>>3)&3) + 6)*dstStride + 32);
    
    #elif defined(HAVE_3DNOW)
    //FIXME check if this is faster on an 3dnow chip or if its faster without the prefetch or ...
    /*				prefetch(vertSrcBlock + (((x>>3)&3) + 2)*srcStride + 32);
    				prefetch(vertSrcBlock + (((x>>3)&3) + 6)*srcStride + 32);
    				prefetchw(vertBlock + (((x>>3)&3) + 2)*dstStride + 32);
    				prefetchw(vertBlock + (((x>>3)&3) + 6)*dstStride + 32);
    */
    
    #endif
    				if(!isColor) yHistogram[ srcBlock[0] ]++;
    
    				blockCopy(vertBlock + dstStride*2, dstStride,
    
    					vertSrcBlock + srcStride*2, srcStride, 8, mode & LEVEL_FIX);
    
    
    
    #ifdef MORE_TIMEING
    				T1= rdtsc();
    				memcpyTime+= T1-T0;
    				T0=T1;
    #endif
    
    				if(mode & V_DEBLOCK)
    
    					if(mode & RK_FILTER)
    						vertRKFilter(vertBlock, stride, QP);
    
    						vertX1Filter(vertBlock, stride, QP);
    					else
    					{
    						if( isVertDC(vertBlock, stride))
    						{
    							if(isVertMinMaxOk(vertBlock, stride, QP))
    								doVertLowPass(vertBlock, stride, QP);
    						}
    						else
    							doVertDefFilter(vertBlock, stride, QP);
    					}
    
    				}
    #ifdef MORE_TIMEING
    				T1= rdtsc();
    				vertTime+= T1-T0;
    				T0=T1;
    #endif
    			}
    			else
    
    				blockCopy(vertBlock + dstStride*1, dstStride,
    					vertSrcBlock + srcStride*1, srcStride, 4, mode & LEVEL_FIX);
    
    
    
    			if(x - 8 >= 0 && x<width)
    			{
    #ifdef MORE_TIMEING
    				T0= rdtsc();
    #endif
    
    				if(mode & H_DEBLOCK)
    
    					if( isHorizDCAndCopy2Temp(dstBlock-4, stride))
    					{
    						if(isHorizMinMaxOk(tempBlock, TEMP_STRIDE, QP))
    							doHorizLowPassAndCopyBack(dstBlock-4, stride, QP);
    					}
    					else
    						doHorizDefFilterAndCopyBack(dstBlock-4, stride, QP);
    
    				}
    #ifdef MORE_TIMEING
    				T1= rdtsc();
    				horizTime+= T1-T0;
    				T0=T1;
    #endif
    				dering(dstBlock - 9 - stride, stride, QP);
    			}
    			else if(y!=0)
    				dering(dstBlock - stride*9 + width-9, stride, QP);
    			//FIXME dering filter will not be applied to last block (bottom right)
    
    
    			dstBlock+=8;
    			srcBlock+=8;
    			vertBlock+=8;
    			vertSrcBlock+=8;
    		}
    	}
    
    #ifdef HAVE_3DNOW
    	asm volatile("femms");
    #elif defined (HAVE_MMX)
    
    	asm volatile("emms");
    #endif
    
    #ifdef TIMEING
    	// FIXME diff is mostly the time spent for rdtsc (should subtract that but ...)
    	sumTime= rdtsc() - sumTime;
    	if(!isColor)