/* yuv2rgb.c : various color-space conversion (YUV->RGB) routines
 *
 * MPEG2AVI
 * --------
 *  v0.16B3  changed var declaration, moved mmx-contansts to global scope,
 *    to help Visual C++ properly align the data.
 *  v0.16B24 fixed incorrect source-address calculation (caused crop
 *    window to always focus on lower-center boundary of source image)
 *  v0.16B24 fixed stupid color shift in yuv444torgb24(), error was 
 *    in the setup for u_src_ptr[] and v_src_ptr[] 
 *    removed y420torgb24(), not in use
 *    
 *  v0.16B23 initial release
 *      MMX-optimized y444rgb24()
 *       (can be adapated to y444rgb32()
 *
 */

#include <stdio.h>

#include "config.h"
#include "global.h"  
#include "yuv2yuv.h" // get t

// the prescale value must be >= 3, it must downscale the largest
// table-coefficient value to fit within a 16-bit signed integer

#define PRESCALE 3				// prescalar for coefficient table
#define RSCALE (16 - PRESCALE)	// prescalar for coefficient table
#define CY_SCALE 76309   // scale value for Y-component

// these variables are declared here, to enforce alignment
static const __int64 mmysub = 0x0010001000100010; // "+16" per pixel 
static const __int64 mmuvsub = 0x0080008000800080; // "+128" per pixel
static const __int64 pxmask000F =0x000000000000FFFF; // isolate pixel[0] of 3210
static const __int64 pxmask0F00 =0x0000FFFF00000000; // isolate pixel[2] of 3210
static const DWORD rndadjust[2] = {1<<(RSCALE-1), 1<<(RSCALE-2) }; // round adjustment


/* integer version, no longer user
yuv444torgb24( unsigned char *fbout, unsigned char *y_src, unsigned char *u_src, 
	unsigned char *v_src, long srcW, long srcH, LPRECT RCrop )
{
  int crv, cbu, cgu, cgv; // matrix coefficients 
  long i=0, j=0; // loop index vars 
  int y=0, u=128, v=128;
  unsigned char r=0, g=0, b=0;
  unsigned long src_addr = 0,dest_addr=0;
  int dest_h = RCrop->bottom - RCrop->top; 
  int dest_w = RCrop->right - RCrop->left;
  //unsigned char *py=NULL, *pu=NULL, *pv=NULL; 
 
  crv = Inverse_Table_6_9[matrix_coefficients][0];
  cbu = Inverse_Table_6_9[matrix_coefficients][1];
  cgu = Inverse_Table_6_9[matrix_coefficients][2];
  cgv = Inverse_Table_6_9[matrix_coefficients][3];
  
  // flip output vertically 
  for (j=0; j<dest_h; j++)
  {
	src_addr = srcW * (RCrop->top + j ); // address of src row
	//dest_addr = 3*(j*dest_w);	  // <== don't flip output vertically
	dest_addr = 3*((dest_h - (j+1))* dest_w); // flip output vertically
	
    for (i=0; i<dest_w; i++)
	{
		// store in temporary display buffer 
		// calculate address of pixel(x,y) in *framebuffer 

		y = 76309 * (y_src[ src_addr + i ] - 16); // (255/219)*65536 
		u = u_src[ src_addr + i ]- 128;
		v = v_src[ src_addr + i ]- 128;

		r = Clip[(y + crv*v + 32768)>>16];
		g = Clip[(y - cgu*u - cgv*v + 32768)>>16];
		b = Clip[(y + cbu*u + 32768)>>16];

			// proper order for BMP RGB24 
		fbout[ dest_addr + 3*i    ] = b;
		fbout[ dest_addr + 3*i + 1] = g;
		fbout[ dest_addr + 3*i + 2] = r;
		
	} // endfor i 
  } // endfor j 
}*/


// convert color space from YUV 4:4:4 planar -> RGB24 24bpp packed 
/* input = (YUV 4/4/4) format ( size = srcRect.right X srcRect.bottom )
	->src1 = y_ptr[], 
	->src2 = u_ptr[], 
	->src3 = v_ptr[]   < srcW * srcH > 
	->dst1 = fbout[] (output buffer) (size = dstRect.right X destRect.bottom )
	Viewport upper-left crop-window ( srcRect.left * srcRect.top )

    output = 24bpp RGB bitmap into fbout[]  (vertically flipped)
*/
void
yuv444torgb24( tImageOpBlock *pConvBlock )
{
  static __int64 scratch0 = 0x0; // scratch space
  static WORD yuvRP1GP1[4]; // YUV multipliers (#1)
  static WORD yuvBP1GP2[4]; // YUV multipliers (#2)
  static DWORD dest_w;
  static DWORD dest_h;
  static DWORD srcW;
  static DWORD srcH;

  static unsigned char *u_src_ptr;
  static unsigned char *v_src_ptr;
  static unsigned char *y_src_ptr;
  static unsigned char *fbout; // output buffer

  WORD cy, crv, cbu, cgu, cgv; /* matrix coefficients */
  short u=128, v=128;
  unsigned char r=0, g=0, b=0;
  int start_row;

  dest_w = pConvBlock->dstRect.right;
  dest_h = pConvBlock->dstRect.bottom;
  srcW = pConvBlock->srcRect.right;
  srcH = pConvBlock->srcRect.bottom;
  start_row = ( srcH - 1 ) - pConvBlock->srcRect.top ;

  u_src_ptr = pConvBlock->src2 + start_row*srcW + pConvBlock->srcRect.left;
  v_src_ptr = pConvBlock->src3+ start_row*srcW + pConvBlock->srcRect.left;
  y_src_ptr = pConvBlock->src1+ start_row*srcW + pConvBlock->srcRect.left;
  fbout = pConvBlock->dst1; // output buffer


  if ( srcW & 0x02 )
  {
	  fprintf( stderr, "\nyuv444rgb24() : Source width (%d) should be div4!", 
		  srcW );
	  exit( ERROR );
  }

  if ( dest_w & 0x02 )
  {
	  fprintf( stderr, "\nyuv444rgb24() : Destination width (%d) should be div4!",
		  dest_w );
	  exit( ERROR );
  }

  cy = ( CY_SCALE >> PRESCALE); 
  crv = ( Inverse_Table_6_9[matrix_coefficients][0] >> PRESCALE );
  cbu = ( Inverse_Table_6_9[matrix_coefficients][1] >> PRESCALE );
  cgu = ( Inverse_Table_6_9[matrix_coefficients][2] ) >> PRESCALE;
  cgv = ( Inverse_Table_6_9[matrix_coefficients][3] ) >> PRESCALE;

  // build YUV multipliers for MMX-routine
  // yuvRP1GP1 = [  cy crv |  cy -cgu ]
  // pixel [RED | pGREEN1] = (yuvRP1GP1) * ([ Y V | Y U ])
  yuvRP1GP1[0] = -cgu;
  yuvRP1GP1[1] = cy;
  yuvRP1GP1[2] = crv;
  yuvRP1GP1[3] = cy;

  // yuvBP1GP2 = [  cy cbu |  0  -cgv ]
  // pixel [BLUE | pGREEN2] = (yuvBP1GP2) * ([ Y U | Y V ])
  yuvBP1GP2[0] = -cgv;
  yuvBP1GP2[1] = 0;
  yuvBP1GP2[2] = cbu;
  yuvBP1GP2[3] = cy;

  // pixel GREEN = (pGREEN1 + pGREEN2)
  

  __asm {	
	mov eax, dword ptr [y_src_ptr]; // eax = y_src;
	 mov esi, 0x00;	// esi = i = 0;
	mov ebx, dword ptr [u_src_ptr]; // ebx = u_src;
	mov ecx, dword ptr [v_src_ptr]; // ecx = v_src;
	mov edx, dword ptr [fbout];	// edx = fb_yuv[]
	mov edi, [dest_h];	// edi = j = dest_h
	
		// start pixel processing logic
		// 1 loop-iteration generates 4 output RGB24 pixels (12 bytes)
		// The routine reads 4 Y pixels, 4 U pixels, & 4 V pixels
		// The rest of the code generates the R, G, and B components
		// individually, packs them, and stores them to temp var scratch0[],
		// and writes the packed DWORDs to fbout[]

	 // for ( y = dest_h; y > 0; y = y - 1 ); // outer loop

		// for ( x = 0; x < dest_w; x += 4); // inner loop
	lp_yuvtorgb :	// begin ofinner loop 
		movd mm0, dword ptr [eax + esi]; // mm0 = y_src[____3210]
		 pxor mm7, mm7;		// clear mm7

		movd mm1, dword ptr [ebx + esi]; // mm1 = u_src[____3210]
		 punpcklbw mm0, mm7;	// mm0 = y_src[_3_2_1_0]
		movd mm2, dword ptr [ecx + esi]; // mm2 = v_src[____3210]
		 punpcklbw mm1, mm7;	// mm1 = u_src[_3_2_1_0]
		psubsw mm0, [mmysub]; // mm0 = y_src[] - 16;
 		 punpcklbw mm2, mm7;	// mm2 = v_src[_3_2_1_0]
		psubsw mm1, [mmuvsub]; // mm1 = u_src[] -128;
		 movq mm4, mm0;		// mm5 = y_src[_3_2_1_0] ready data
		psubsw mm2, [mmuvsub]; // mm2 = v_src[] -128;
		// data is ready to be processed
		// mm0 = y[_3_2_1_0], mm1 = u[_3_2_1_0], mm2 = v[_3_2_1_0]

		// copy them into mm4,mm5,mm6 (respectively)

		 movq mm5, mm1;		// mm6 = u_src[_3_2_1_0] ready data
		movq mm6, mm2;		// mm7 = v_src[_3_2_1_0] ready data

	// pixel#1 processing 
		 punpcklwd mm0, mm7;	// mm0 = [ __Y1 __Y0 ]

		pand mm1, [pxmask000F]; // mm1 = [ __ __ __ U0 ];
		 punpckldq mm0, mm0;	// mm0 = [ __Y0 __Y0 ];

		pand mm2, [pxmask000F]; // mm2 = [ __ __ __ V0 ];
		 psllq mm1, 32;		// shift u_src[] , mm1 = [ __ U0 __ __ ];

		por mm1, mm2;		// mm0 = [ Y0 __| Y0 V0 ]
		 psllq mm0, 16;	// mm0 = [ Y0__ Y0__ ]

		movq mm3, [yuvRP1GP1]; // mm3 = [ cy crv | cy cgu ] multipliers
		 por mm0, mm1;		// mm0 = [ Y0 U0| Y0 V0 ] READY DATA!

		movq mm1, mm0;	// copy data, mm1 = [  Y0 U0|Y0 V0 ] READY DATA!
		 psrlq mm0, 32;	// mm0 = [ __ __|Y0 U0]

		movq mm2, [rndadjust];	// mm2 = (round adjustment)
		 punpckldq mm0, mm1;	// mm0 = [ Y0 V0| Y0 U0 ]
		
		pmaddwd mm0, mm3;	// compute 1ST result
//		 punpckhdq mm1, mm1;	// mm1 = [ Y0 U0 | Y0 U0 ]

		pmaddwd mm1, [yuvBP1GP2];	// compute 2nd result
		 ;// slot

		;// result 1 = [ PIXEL RED | pPIXEL1 GREEN]
		;// result 2 = [ PIXEL BLUE| pPIXEL2 GREEN]

		movq mm7, [pxmask0F00 ]; // mm7 = [ 00 FF | 00 00 ]
		 paddd mm0, mm2;	// mm0 = (1st-result) + (round adjustment)
		 
		movq mm3, mm0;	// copy mm0, mm3 = (1st-result) + (round adjustment)
		 paddd mm1, mm2; // mm1 = (2nd-result) + (round adjustment)

		psrad mm3, RSCALE; // mm3 = [ PIXEL_RED(scaled to 8bit) | garbage ]
		 paddd mm0, mm1; // mm0 = [ garbage | PIXEL GREEN ]

		pand mm3, mm7; // mm3= [ ___ RED | ___ ___ ]
		 psrad mm1, RSCALE; // mm1 = [ PIXEL_BLUE(scaled to 8bit) | garbage ]

		pand mm1, mm7;  // mm1= [ ___ BLUE| ___ ___ ]
		 psrad mm0, RSCALE; // mm0 = [ garbage | pixel_GREEN(scaled to 8bit) ]

		pand mm0, [ pxmask000F]; // mm0 = [ ____ ____ | ____GREEN ]
		 psrlq mm1, 32; // mm1 = [ ___ ___ | ___BLUE]

		psllq mm0, 16; // mm0 = [ ____ ____ | GREEN____ ]
		 por mm1, mm3;	// mm1 = [ ___ RED | ___ BLUE ]

		por mm0, mm1;  // mm0 = [ ___ RED | GREEN BLUE ] ; // almost done!
		 pxor mm2, mm2;// clear mm2

		//the pack operation automatically clips the pixel values to 0-255
		packuswb mm0, mm2; // mm0 = [ __ __ | _R GB ]; // final data
	// done with pixel #1, now store it to scratch space
		 
		 movq mm2, mm6;	// reload mm2 with U[ 3 2 1 0]

		movq mm1, mm5; // reload mm1 with V[ 3 2 1 0]
		 psrlq mm2, 16;	// position mm2 @ pixel1 V[ _ 3 2 1 ]
		
		movq [scratch0], mm0;	// scratch0 <= mm0
		 psrlq mm1, 16; // position mm1 @ pixel1 U[ _ 3 2 1 ]
		
		movq mm0, mm4;	// reload mm0 with Y[ 3 2 1 0]
		 psrlq mm0, 16; // position mm0 @ pixel1 Y[ _ 3 2 1 ]

		pxor mm7, mm7; // clear mm7

	// begin pixel#2 processing here
		 punpcklwd mm0, mm7;	// mm0 = [ __Y1 __Y0 ]

		pand mm1, [pxmask000F]; // mm1 = [ __ __ __ U0 ];
		 punpckldq mm0, mm0;	// mm0 = [ __Y0 __Y0 ];

		pand mm2, [pxmask000F]; // mm2 = [ __ __ __ V0 ];
		 psllq mm1, 32;		// shift u_src[] , mm1 = [ __ U0 __ __ ];

		por mm1, mm2;		// mm0 = [ Y0 __| Y0 V0 ]
		 psllq mm0, 16;	// mm0 = [ Y0__ Y0__ ]

		movq mm3, [yuvRP1GP1]; // mm3 = [ cy crv | cy cgu ] multipliers
		 por mm0, mm1;		// mm0 = [ Y0 U0| Y0 V0 ] READY DATA!

		movq mm1, mm0;	// copy data, mm1 = [  Y0 U0|Y0 V0 ] READY DATA!
		 psrlq mm0, 32;	// mm0 = [ __ __|Y0 U0]

		movq mm2, [rndadjust];	// mm2 = (round adjustment)
		 punpckldq mm0, mm1;	// mm0 = [ Y0 V0| Y0 U0 ]
		
		pmaddwd mm0, mm3;	// compute 1ST result
//		 punpckhdq mm1, mm1;	// mm1 = [ Y0 U0 | Y0 U0 ]

		pmaddwd mm1, [yuvBP1GP2];	// compute 2nd result
		 ;// slot

		;// result 1 = [ PIXEL RED | pPIXEL GREEN]
		;// result 2 = [ PIXEL BLUE| pPIXEL GREEN]

		movq mm7, [pxmask0F00 ]; // mm7 = [ 00 FF | 00 00 ]
		 paddd mm0, mm2;	// mm0 = (1st-result) + (round adjustment)
		 
		movq mm3, mm0;	// copy mm0, mm3 = (1st-result) + (round adjustment)
		 paddd mm1, mm2; // mm1 = (2nd-result) + (round adjustment)

		psrad mm3, RSCALE; // mm3 = [ PIXEL_RED(scaled to 8bit) | garbage ]
		 paddd mm0, mm1; // mm0 = [ garbage | PIXEL GREEN ]

		pand mm3, mm7; // mm3= [ ___ RED | ___ ___ ]
		 psrad mm1, RSCALE; // mm1 = [ PIXEL_BLUE(scaled to 8bit) | garbage ]

		pand mm1, mm7;  // mm1= [ ___ BLUE| ___ ___ ]
		 psrad mm0, RSCALE; // mm0 = [ garbage | pixel_GREEN(scaled to 8bit) ]

		pand mm0, [ pxmask000F]; // mm0 = [ ____ ____ | ____GREEN ]
		 psrlq mm1, 32; // mm1 = [ ___ ___ | ___BLUE]

		psllq mm0, 16; // mm0 = [ ____ ____ | GREEN____ ]
		 por mm1, mm3;	// mm1 = [ ___ RED | ___ BLUE ]

		por mm0, mm1;  // mm0 = [ ___ RED | GREEN BLUE ] ; // almost done!
		 pxor mm2, mm2;// clear mm2

		//the pack operation automatically clips the pixel values to 0-255
		movq mm1, [scratch0];	// scratch0 <= mm0
		 packuswb mm0, mm2; // mm0 = [ __ __ | _R GB ]; // final data
	
	// done with pixel #2, now merge with pixel#1 (stored @ scratch0)
		psllq mm0, 24;	// mm0 = [ __ RG | B_ __ ] (current pixel)

		por mm0, mm1;	// mm0 = [ __ RG | BR GB ] (pixel[1] | pixel[0])
		 movq mm2, mm6;	 // reload mm2 with V[_3_2_1_0]

		movq mm1, mm5;  // reload mm0 with Y[_3_2_1_0]
		 movq mm3, mm0;	// copy mm0 to mm3

		movd dword ptr [ edx ], mm0;	// store 1st-quad to fbout[]
		 psrlq mm3, 32;	// mm1 = [ __ __ | __ RG ], residual pixel#2

		movq mm0, mm4;	 // reload mm0 with Y[_3_2_1_0]
		 psrlq mm2, 32;	// position mm2 @ pixel2 V[ _ _ 3 2 ]

		movq [scratch0], mm3;	// store residual to scratch
		 psrlq mm0, 32;	// position mm0 @ pixel2 Y[ _ _ 3 2 ]
		
		pxor mm7, mm7; // clear mm7
		 psrlq mm1, 32;	// position mm1 @ pixel2 U[ _ _ 3 2 ]

	// done storing pixel #2, begin pixel #3 processing
		punpcklwd mm0, mm7;	// mm0 = [ __Y1 __Y0 ]

		pand mm1, [pxmask000F]; // mm1 = [ __ __ __ U0 ];
		 punpckldq mm0, mm0;	// mm0 = [ __Y0 __Y0 ];

		pand mm2, [pxmask000F]; // mm2 = [ __ __ __ V0 ];
		 psllq mm1, 32;		// shift u_src[] , mm1 = [ __ U0 __ __ ];

		por mm1, mm2;		// mm0 = [ Y0 __| Y0 V0 ]
		 psllq mm0, 16;	// mm0 = [ Y0__ Y0__ ]

		movq mm3, [yuvRP1GP1]; // mm3 = [ cy crv | cy cgu ] multipliers
		 por mm0, mm1;		// mm0 = [ Y0 U0| Y0 V0 ] READY DATA!

		movq mm1, mm0;	// copy data, mm1 = [  Y0 U0|Y0 V0 ] READY DATA!
		 psrlq mm0, 32;	// mm0 = [ __ __|Y0 U0]

		movq mm2, [rndadjust];	// mm2 = (round adjustment)
		 punpckldq mm0, mm1;	// mm0 = [ Y0 V0| Y0 U0 ]
		
		pmaddwd mm0, mm3;	// compute 1ST result
//		 punpckhdq mm1, mm1;	// mm1 = [ Y0 U0 | Y0 U0 ]

		pmaddwd mm1, [yuvBP1GP2];	// compute 2nd result
		 ;// slot

		;// result 1 = [ PIXEL RED | pPIXEL GREEN]
		;// result 2 = [ PIXEL BLUE| pPIXEL GREEN]

		movq mm7, [pxmask0F00 ]; // mm7 = [ 00 FF | 00 00 ]
		 paddd mm0, mm2;	// mm0 = (1st-result) + (round adjustment)
		 
		movq mm3, mm0;	// copy mm0, mm3 = (1st-result) + (round adjustment)
		 paddd mm1, mm2; // mm1 = (2nd-result) + (round adjustment)

		psrad mm3, RSCALE; // mm3 = [ PIXEL_RED(scaled to 8bit) | garbage ]
		 paddd mm0, mm1; // mm0 = [ garbage | PIXEL GREEN ]

		pand mm3, mm7; // mm3= [ ___ RED | ___ ___ ]
		 psrad mm1, RSCALE; // mm1 = [ PIXEL_BLUE(scaled to 8bit) | garbage ]

		pand mm1, mm7;  // mm1= [ ___ BLUE| ___ ___ ]
		 psrad mm0, RSCALE; // mm0 = [ garbage | pixel_GREEN(scaled to 8bit) ]

		pand mm0, [ pxmask000F]; // mm0 = [ ____ ____ | ____GREEN ]
		 psrlq mm1, 32; // mm1 = [ ___ ___ | ___BLUE]

		psllq mm0, 16; // mm0 = [ ____ ____ | GREEN____ ]
		 por mm1, mm3;	// mm1 = [ ___ RED | ___ BLUE ]

		por mm0, mm1;  // mm0 = [ ___ RED | GREEN BLUE ] ; // almost done!
		 pxor mm2, mm2;// clear mm2

		//the pack operation automatically clips the pixel values to 0-255
		movq mm1, [scratch0];	// scratch0 <= mm0
		 packuswb mm0, mm2; // mm0 = [ __ __ | _R GB ]; // final data
	
	// done with pixel #3, now merge with pixel#2 (stored @ scratch0)
		psllq mm0, 16;	// mm0 = [ __ _R | GB __ ] current pixel (#3)

		por mm0, mm1;	// mm0 = [ __ _R | GB RG ] (pixel[3] | pixel[2])
						//             3   33 22, residual pixel2
		 movq mm2, mm6;	 // reload mm2 with V[_3_2_1_0]

		movq mm1, mm5;  // reload mm0 with Y[_3_2_1_0]
		 movq mm3, mm0;	// copy mm0 to mm3

		movd dword ptr [ edx + 4 ], mm0;	// store 2nd-quad to fbout[]
		 psrlq mm3, 32;	// mm1 = [ __ __ | __ _R ], residual pixel#3

		movq mm0, mm4;	 // reload mm0 with Y[_3_2_1_0]
		 psrlq mm2, 48;	// position mm2 @ pixel3 V[ _ _ _ 3 ]

		movq [scratch0], mm3;	// store residual to scratch
		 psrlq mm0, 48;	// position mm0 @ pixel3 Y[ _ _ _ 3 ]

 		pxor mm7, mm7; // clear mm7
		 psrlq mm1, 48;	// position mm1 @ pixel3 U[ _ _ _ 3 ]

	// done storing pixel #3, begin pixel #4 processing
		 punpcklwd mm0, mm7;	// mm0 = [ __Y1 __Y0 ]

		pand mm1, [pxmask000F]; // mm1 = [ __ __ __ U0 ];
		 punpckldq mm0, mm0;	// mm0 = [ __Y0 __Y0 ];

		pand mm2, [pxmask000F]; // mm2 = [ __ __ __ V0 ];
		 psllq mm1, 32;		// shift u_src[] , mm1 = [ __ U0 __ __ ];

		por mm1, mm2;		// mm0 = [ Y0 __| Y0 V0 ]
		 psllq mm0, 16;	// mm0 = [ Y0__ Y0__ ]

		movq mm3, [yuvRP1GP1]; // mm3 = [ cy crv | cy cgu ] multipliers
		 por mm0, mm1;		// mm0 = [ Y0 U0| Y0 V0 ] READY DATA!

		movq mm1, mm0;	// copy data, mm1 = [  Y0 U0|Y0 V0 ] READY DATA!
		 psrlq mm0, 32;	// mm0 = [ __ __|Y0 U0]

		movq mm2, [rndadjust];	// mm2 = (round adjustment)
		 punpckldq mm0, mm1;	// mm0 = [ Y0 V0| Y0 U0 ]
		
		pmaddwd mm0, mm3;	// compute 1ST result
//		 punpckhdq mm1, mm1;	// mm1 = [ Y0 U0 | Y0 U0 ]

		pmaddwd mm1, [yuvBP1GP2];	// compute 2nd result
		 ;// slot

		;// result 1 = [ PIXEL RED | pPIXEL GREEN]
		;// result 2 = [ PIXEL BLUE| pPIXEL GREEN]

		movq mm7, [pxmask0F00 ]; // mm7 = [ 00 FF | 00 00 ]
		 paddd mm0, mm2;	// mm0 = (1st-result) + (round adjustment)
		 
		movq mm3, mm0;	// copy mm0, mm3 = (1st-result) + (round adjustment)
		 paddd mm1, mm2; // mm1 = (2nd-result) + (round adjustment)

		psrad mm3, RSCALE; // mm3 = [ PIXEL_RED(scaled to 8bit) | garbage ]
		 paddd mm0, mm1; // mm0 = [ garbage | PIXEL GREEN ]

		pand mm3, mm7; // mm3= [ ___ RED | ___ ___ ]
		 psrad mm1, RSCALE; // mm1 = [ PIXEL_BLUE(scaled to 8bit) | garbage ]

		pand mm1, mm7;  // mm1= [ ___ BLUE| ___ ___ ]
		 psrad mm0, RSCALE; // mm0 = [ garbage | pixel_GREEN(scaled to 8bit) ]

		pand mm0, [ pxmask000F]; // mm0 = [ ____ ____ | ____GREEN ]
		 psrlq mm1, 32; // mm1 = [ ___ ___ | ___BLUE]

		psllq mm0, 16; // mm0 = [ ____ ____ | GREEN____ ]
		 por mm1, mm3;	// mm1 = [ ___ RED | ___ BLUE ]

		por mm0, mm1;  // mm0 = [ ___ RED | GREEN BLUE ] ; // almost done!
		 pxor mm2, mm2;// clear mm2

		//the pack operation automatically clips the pixel values to 0-255
		movq mm1, [scratch0];	// scratch0 <= mm0
		 packuswb mm0, mm2; // mm0 = [ __ __ | _R GB ]; // final data
	
	// done with pixel #4, now merge with pixel#3 (stored @ scratch0)
		psllq mm0, 8;	// mm0 = [ __ __ | RG B_ ] current pixel (#4)

		por mm0, mm1;	// mm0 = [ __ __ | RG BR ] (pixel[4] | pixel[3])
						//                 44 43, residual pixel3
		 pxor mm7, mm7; // clear mm7

		movq [scratch0], mm2;	// clear residual
		 add esi, 0x04;	// x = x+4;

		movd dword ptr [ edx + 8 ], mm0;	// store 3rd-quad to fbout[]
		 add edx, 12;	// fbout += 12;  advance 4 pixels (12 bytes)

	// that's it, we've written 4 RGB24 pixels (12-bytes) !
		cmp esi, [dest_w]; // compare ( x <> dest_w )
		 jl lp_yuvtorgb;	// end for ( x = 0; x < dest_w; x += 4);

	sub eax, [srcW];	// y_src -= 1 row
	 sub edi, 0x01;	// y = y -1;
	sub ebx, [srcW];	// y_src -= 1 row
	 mov esi, 0x00;	// x = 0;
	sub ecx, [srcW];	// y_src -= 1 row
	 cmp edi, 0x00; // compare ( y <> 0 )

	jg lp_yuvtorgb;	// end for ( y = dest_h; y > 0; --y )

	emms;

	} // end __asm

/*  the inner loop of the MMX code is equivalent to this inner loop
    for (i=0; i<dest_w; i+=4)
	{
		// store in temporary display buffer 
		// calculate address of pixel(x,y) in *framebuffer 

      { // process 4 output RGB24 pixels at once 
		y = 38155 * ((y_src[ src_addr + i ] - 16) << 1 ); // (255/219)*65536 
		u = (u_src[ src_addr + i ]- 128) << 3;
		v = (v_src[ src_addr + i ]- 128) << 3;

		r = Clip[(y + crv*v + 32768)>>16];
		g = Clip[(y - cgu*u - cgv*v + 32768)>>16];
		b = Clip[(y + cbu*u + 32768)>>16];

			// proper order for BMP RGB24 
		fbout[ dest_addr + 3*i    ] = b;
		fbout[ dest_addr + 3*i + 1] = g;
		fbout[ dest_addr + 3*i + 2] = r;
		
	} // endfor i 
	*/

} // end function y444rgb24()  [ MMX version ]


/* convert color space from YUV420 24bpp -> RGB24 24bpp packed */
/* In this instance, the input is a 24bpp packed image, the
   Y-plane is at full resolution ( g_AVIcropX * g_AVIcropY )
   The U/V planes are at half-resolution.
   Thus, 1 input UV/pixel is used for 4 RGB output pixels.
/* output = 24bpp RGB  bitmap of ( g_AVIcropX * g_AVIcropY )
void
y420rgb24( unsigned char fb[], LPRECT RCrop )
{
	int crv, cbu, cgu, cgv; // matrix coefficients 
  long i, j; // loop index vars 
  int y, u, v, r, g, b;
  unsigned long addr, uv_addr;
  int dest_h = RCrop->bottom - RCrop->top; 
  int dest_w = RCrop->right - RCrop->left;
  //unsigned char *py=NULL, *pu=NULL, *pv=NULL; 
 
  crv = Inverse_Table_6_9[matrix_coefficients][0];
  cbu = Inverse_Table_6_9[matrix_coefficients][1];
  cgu = Inverse_Table_6_9[matrix_coefficients][2];
  cgv = Inverse_Table_6_9[matrix_coefficients][3];
  for ( j = dest_h-1; (j >= 0); --j )
  {
    for ( i = dest_w-1; (i >= 0); --i )
	{
		// store in temporary display buffer 
		// calculate address of pixel(x,y) in *framebuffer 
		addr = 3*(j* dest_w + i);
		uv_addr = 3*( (j>>1) * (dest_w) + (i>>1 ) );
		y = 76309 * (*(fb + addr ) - 16); // (255/219)*65536 
		u = *(fb + uv_addr + 1) - 128;
		v = *(fb + uv_addr + 2) - 128;
		r = Clip[(y + crv*v + 32768)>>16];
		g = Clip[(y - cgu*u - cgv*v + 32768)>>16];
		b = Clip[(y + cbu*u + 32786)>>16];

		*( fb + addr + 0 ) = b;	// proper order for BMP RGB24
		*( fb + addr + 1 ) = g;	// proper order for BMP RGB24
		*( fb + addr + 2 ) = r;	// proper order for BMP RGB24
		
	} // endfor i
  } // endfor j
}*/


void
yuv444torgb32( tImageOpBlock *pConvBlock )
{
  static WORD yuvRP1GP1[4] ; // YUV multipliers (#1)
  static WORD yuvBP1GP2[4] ; // YUV multipliers (#2)
  static unsigned long start_row;
  static DWORD dest_w;
  static DWORD dest_h;
  static DWORD srcW;
  static DWORD srcH;

  static unsigned char *u_src_ptr;
  static unsigned char *v_src_ptr;
  static unsigned char *y_src_ptr;
  static unsigned char *fbout; // output buffer

  WORD cy, crv, cbu, cgu, cgv; /* matrix coefficients */
  //unsigned char *py=NULL, *pu=NULL, *pv=NULL; 

  dest_w = pConvBlock->dstRect.right;
  dest_h = pConvBlock->dstRect.bottom;
  srcW = pConvBlock->srcRect.right;
  srcH = pConvBlock->srcRect.bottom;

  // calculate starting row#, (inverted from top)
  start_row = ( srcH - 1 ) - pConvBlock->srcRect.top;

  u_src_ptr = pConvBlock->src2+start_row*srcW + pConvBlock->srcRect.left;
  v_src_ptr = pConvBlock->src3+start_row*srcW + pConvBlock->srcRect.left;
  y_src_ptr = pConvBlock->src1+start_row*srcW + pConvBlock->srcRect.left;
  fbout = pConvBlock->dst1; // output buffer

  if ( srcW & 0x02 )
  {
	  fprintf( stderr, "\nyuv444rgb32() : Source width (%d) should be div4!", 
		  srcW );
	  exit( ERROR );
  }

  if ( dest_w & 0x02 )
  {
	  fprintf( stderr, "\nyuv444rgb32() : Destination width (%d) should be div4!",
		  dest_w );
	  exit( ERROR );
  }

  cy = ( CY_SCALE >> PRESCALE); 
  crv = ( Inverse_Table_6_9[matrix_coefficients][0] >> PRESCALE );
  cbu = ( Inverse_Table_6_9[matrix_coefficients][1] >> PRESCALE );
  cgu = ( Inverse_Table_6_9[matrix_coefficients][2] ) >> PRESCALE;
  cgv = ( Inverse_Table_6_9[matrix_coefficients][3] ) >> PRESCALE;

  // build YUV multipliers for MMX-routine
  // yuvRP1GP1 = [  cy crv |  cy -cgu ]
  // pixel [RED | pGREEN1] = (yuvRP1GP1) * ([ Y V | Y U ])
  yuvRP1GP1[0] = -cgu;
  yuvRP1GP1[1] = cy;
  yuvRP1GP1[2] = crv;
  yuvRP1GP1[3] = cy;

  // yuvBP1GP2 = [  cy cbu |  0  -cgv ]
  // pixel [BLUE | pGREEN2] = (yuvBP1GP2) * ([ Y U | Y V ])
  yuvBP1GP2[0] = -cgv;
  yuvBP1GP2[1] = 0;
  yuvBP1GP2[2] = cbu;
  yuvBP1GP2[3] = cy;

  // pixel GREEN = (pGREEN1 + pGREEN2)
  
  __asm {	
	mov eax, dword ptr [y_src_ptr]; // eax = y_src;
	 mov esi, 0x00;	// esi = i = 0;
	mov ebx, dword ptr [u_src_ptr]; // ebx = u_src;
	mov ecx, dword ptr [v_src_ptr]; // ecx = v_src;
	mov edx, dword ptr [fbout];	// edx = fb_yuv[]
	mov edi, [dest_h];	// edi = j = dest_h
	
		// start pixel processing logic
		// 1 loop-iteration generates 4 output RGB24 pixels (12 bytes)
		// The routine reads 4 Y pixels, 4 U pixels, & 4 V pixels
		// The rest of the code generates the R, G, and B components
		// individually, packs them, and stores them to temp var scratch0[],
		// and writes the packed DWORDs to fbout[]

	 // for ( y = dest_h; y > 0; y = y - 1 ); // outer loop

		// for ( x = 0; x < dest_w; x += 4); // inner loop
	lp_yuvtorgb :	// begin ofinner loop 
		movd mm0, dword ptr [eax + esi]; // mm0 = y_src[____3210]
		 pxor mm7, mm7;		// clear mm7

		movd mm1, dword ptr [ebx + esi]; // mm1 = u_src[____3210]
		 punpcklbw mm0, mm7;	// mm0 = y_src[_3_2_1_0]
		movd mm2, dword ptr [ecx + esi]; // mm2 = v_src[____3210]
		 punpcklbw mm1, mm7;	// mm1 = u_src[_3_2_1_0]
		psubsw mm0, [mmysub]; // mm0 = y_src[] - 16;
 		 punpcklbw mm2, mm7;	// mm2 = v_src[_3_2_1_0]
		psubsw mm1, [mmuvsub]; // mm1 = u_src[] -128;
		 movq mm4, mm0;		// mm5 = y_src[_3_2_1_0] ready data
		psubsw mm2, [mmuvsub]; // mm2 = v_src[] -128;
		// data is ready to be processed
		// mm0 = y[_3_2_1_0], mm1 = u[_3_2_1_0], mm2 = v[_3_2_1_0]

		// copy them into mm4,mm5,mm6 (respectively)

		 movq mm5, mm1;		// mm6 = u_src[_3_2_1_0] ready data
		movq mm6, mm2;		// mm7 = v_src[_3_2_1_0] ready data

	// pixel#1 processing 
		 punpcklwd mm0, mm7;	// mm0 = [ __Y1 __Y0 ]

		pand mm1, [pxmask000F]; // mm1 = [ __ __ __ U0 ];
		 punpckldq mm0, mm0;	// mm0 = [ __Y0 __Y0 ];

		pand mm2, [pxmask000F]; // mm2 = [ __ __ __ V0 ];
		 psllq mm1, 32;		// shift u_src[] , mm1 = [ __ U0 __ __ ];

		por mm1, mm2;		// mm0 = [ Y0 __| Y0 V0 ]
		 psllq mm0, 16;	// mm0 = [ Y0__ Y0__ ]

		movq mm3, [yuvRP1GP1]; // mm3 = [ cy crv | cy cgu ] multipliers
		 por mm0, mm1;		// mm0 = [ Y0 U0| Y0 V0 ] READY DATA!

		movq mm1, mm0;	// copy data, mm1 = [  Y0 U0|Y0 V0 ] READY DATA!
		 psrlq mm0, 32;	// mm0 = [ __ __|Y0 U0]

		movq mm2, [rndadjust];	// mm2 = (round adjustment)
		 punpckldq mm0, mm1;	// mm0 = [ Y0 V0| Y0 U0 ]
		
		pmaddwd mm0, mm3;	// compute 1ST result
//		 punpckhdq mm1, mm1;	// mm1 = [ Y0 U0 | Y0 U0 ]

		pmaddwd mm1, [yuvBP1GP2];	// compute 2nd result
		 ;// slot

		;// result 1 = [ PIXEL RED | pPIXEL1 GREEN]
		;// result 2 = [ PIXEL BLUE| pPIXEL2 GREEN]

		movq mm7, [pxmask0F00 ]; // mm7 = [ 00 FF | 00 00 ]
		 paddd mm0, mm2;	// mm0 = (1st-result) + (round adjustment)
		 
		movq mm3, mm0;	// copy mm0, mm3 = (1st-result) + (round adjustment)
		 paddd mm1, mm2; // mm1 = (2nd-result) + (round adjustment)

		psrad mm3, RSCALE; // mm3 = [ PIXEL_RED(scaled to 8bit) | garbage ]
		 paddd mm0, mm1; // mm0 = [ garbage | PIXEL GREEN ]

		pand mm3, mm7; // mm3= [ ___ RED | ___ ___ ]
		 psrad mm1, RSCALE; // mm1 = [ PIXEL_BLUE(scaled to 8bit) | garbage ]

		pand mm1, mm7;  // mm1= [ ___ BLUE| ___ ___ ]
		 psrad mm0, RSCALE; // mm0 = [ garbage | pixel_GREEN(scaled to 8bit) ]

		pand mm0, [ pxmask000F]; // mm0 = [ ____ ____ | ____GREEN ]
		 psrlq mm1, 32; // mm1 = [ ___ ___ | ___BLUE]

		psllq mm0, 16; // mm0 = [ ____ ____ | GREEN____ ]
		 por mm1, mm3;	// mm1 = [ ___ RED | ___ BLUE ]

		por mm0, mm1;  // mm0 = [ ___ RED | GREEN BLUE ] ; // almost done!
		 pxor mm2, mm2;// clear mm2

		//the pack operation automatically clips the pixel values to 0-255
		packuswb mm0, mm2; // mm0 = [ __ __ | _R GB ]; // final data
	// done with pixel #1, now store it to fbout[]
		 
		 movq mm2, mm6;	// reload mm2 with U[ 3 2 1 0]

		movq mm1, mm5; // reload mm1 with V[ 3 2 1 0]
		 psrlq mm2, 16;	// position mm2 @ pixel1 V[ _ 3 2 1 ]
		
		movd [edx ], mm0;	// fbout[ pixel0 ] <= mm0
		 psrlq mm1, 16; // position mm1 @ pixel1 U[ _ 3 2 1 ]
		
		movq mm0, mm4;	// reload mm0 with Y[ 3 2 1 0]
		 psrlq mm0, 16; // position mm0 @ pixel1 Y[ _ 3 2 1 ]

		pxor mm7, mm7; // clear mm7

	// begin pixel#2 processing here
		 punpcklwd mm0, mm7;	// mm0 = [ __Y1 __Y0 ]

		pand mm1, [pxmask000F]; // mm1 = [ __ __ __ U0 ];
		 punpckldq mm0, mm0;	// mm0 = [ __Y0 __Y0 ];

		pand mm2, [pxmask000F]; // mm2 = [ __ __ __ V0 ];
		 psllq mm1, 32;		// shift u_src[] , mm1 = [ __ U0 __ __ ];

		por mm1, mm2;		// mm0 = [ Y0 __| Y0 V0 ]
		 psllq mm0, 16;	// mm0 = [ Y0__ Y0__ ]

		movq mm3, [yuvRP1GP1]; // mm3 = [ cy crv | cy cgu ] multipliers
		 por mm0, mm1;		// mm0 = [ Y0 U0| Y0 V0 ] READY DATA!

		movq mm1, mm0;	// copy data, mm1 = [  Y0 U0|Y0 V0 ] READY DATA!
		 psrlq mm0, 32;	// mm0 = [ __ __|Y0 U0]

		movq mm2, [rndadjust];	// mm2 = (round adjustment)
		 punpckldq mm0, mm1;	// mm0 = [ Y0 V0| Y0 U0 ]
		
		pmaddwd mm0, mm3;	// compute 1ST result
//		 punpckhdq mm1, mm1;	// mm1 = [ Y0 U0 | Y0 U0 ]

		pmaddwd mm1, [yuvBP1GP2];	// compute 2nd result
		 ;// slot

		;// result 1 = [ PIXEL RED | pPIXEL GREEN]
		;// result 2 = [ PIXEL BLUE| pPIXEL GREEN]

		movq mm7, [pxmask0F00 ]; // mm7 = [ 00 FF | 00 00 ]
		 paddd mm0, mm2;	// mm0 = (1st-result) + (round adjustment)
		 
		movq mm3, mm0;	// copy mm0, mm3 = (1st-result) + (round adjustment)
		 paddd mm1, mm2; // mm1 = (2nd-result) + (round adjustment)

		psrad mm3, RSCALE; // mm3 = [ PIXEL_RED(scaled to 8bit) | garbage ]
		 paddd mm0, mm1; // mm0 = [ garbage | PIXEL GREEN ]

		pand mm3, mm7; // mm3= [ ___ RED | ___ ___ ]
		 psrad mm1, RSCALE; // mm1 = [ PIXEL_BLUE(scaled to 8bit) | garbage ]

		pand mm1, mm7;  // mm1= [ ___ BLUE| ___ ___ ]
		 psrad mm0, RSCALE; // mm0 = [ garbage | pixel_GREEN(scaled to 8bit) ]

		pand mm0, [ pxmask000F]; // mm0 = [ ____ ____ | ____GREEN ]
		 psrlq mm1, 32; // mm1 = [ ___ ___ | ___BLUE]

		psllq mm0, 16; // mm0 = [ ____ ____ | GREEN____ ]
		 por mm1, mm3;	// mm1 = [ ___ RED | ___ BLUE ]

		por mm0, mm1;  // mm0 = [ ___ RED | GREEN BLUE ] ; // almost done!
		 pxor mm2, mm2;// clear mm2

		//the pack operation automatically clips the pixel values to 0-255
		packuswb mm0, mm2; // mm0 = [ __ __ | _R GB ]; // final data
	
	// done with pixel #2, now merge with pixel#1 (stored @ scratch0)
		 movq mm2, mm6;	 // reload mm2 with V[_3_2_1_0]

		movq mm1, mm5;  // reload mm0 with Y[_3_2_1_0]
		 movq mm3, mm0;	// copy mm0 to mm3

		movd dword ptr [ edx + 4], mm0;	// store 2nd pixel to fbout[]
		 psrlq mm1, 32;	// position mm1 @ pixel2 U[ _ _ 3 2 ]

		movq mm0, mm4;	 // reload mm0 with Y[_3_2_1_0]
		 psrlq mm2, 32;	// position mm2 @ pixel2 V[ _ _ 3 2 ]

		pxor mm7, mm7; // clear mm7
		 psrlq mm0, 32;	// position mm0 @ pixel2 Y[ _ _ 3 2 ]

	// done storing pixel #2, begin pixel #3 processing
		punpcklwd mm0, mm7;	// mm0 = [ __Y1 __Y0 ]

		pand mm1, [pxmask000F]; // mm1 = [ __ __ __ U0 ];
		 punpckldq mm0, mm0;	// mm0 = [ __Y0 __Y0 ];

		pand mm2, [pxmask000F]; // mm2 = [ __ __ __ V0 ];
		 psllq mm1, 32;		// shift u_src[] , mm1 = [ __ U0 __ __ ];

		por mm1, mm2;		// mm0 = [ Y0 __| Y0 V0 ]
		 psllq mm0, 16;	// mm0 = [ Y0__ Y0__ ]

		movq mm3, [yuvRP1GP1]; // mm3 = [ cy crv | cy cgu ] multipliers
		 por mm0, mm1;		// mm0 = [ Y0 U0| Y0 V0 ] READY DATA!

		movq mm1, mm0;	// copy data, mm1 = [  Y0 U0|Y0 V0 ] READY DATA!
		 psrlq mm0, 32;	// mm0 = [ __ __|Y0 U0]

		movq mm2, [rndadjust];	// mm2 = (round adjustment)
		 punpckldq mm0, mm1;	// mm0 = [ Y0 V0| Y0 U0 ]
		
		pmaddwd mm0, mm3;	// compute 1ST result
//		 punpckhdq mm1, mm1;	// mm1 = [ Y0 U0 | Y0 U0 ]

		pmaddwd mm1, [yuvBP1GP2];	// compute 2nd result
		 ;// slot

		;// result 1 = [ PIXEL RED | pPIXEL GREEN]
		;// result 2 = [ PIXEL BLUE| pPIXEL GREEN]

		movq mm7, [pxmask0F00 ]; // mm7 = [ 00 FF | 00 00 ]
		 paddd mm0, mm2;	// mm0 = (1st-result) + (round adjustment)
		 
		movq mm3, mm0;	// copy mm0, mm3 = (1st-result) + (round adjustment)
		 paddd mm1, mm2; // mm1 = (2nd-result) + (round adjustment)

		psrad mm3, RSCALE; // mm3 = [ PIXEL_RED(scaled to 8bit) | garbage ]
		 paddd mm0, mm1; // mm0 = [ garbage | PIXEL GREEN ]

		pand mm3, mm7; // mm3= [ ___ RED | ___ ___ ]
		 psrad mm1, RSCALE; // mm1 = [ PIXEL_BLUE(scaled to 8bit) | garbage ]

		pand mm1, mm7;  // mm1= [ ___ BLUE| ___ ___ ]
		 psrad mm0, RSCALE; // mm0 = [ garbage | pixel_GREEN(scaled to 8bit) ]

		pand mm0, [ pxmask000F]; // mm0 = [ ____ ____ | ____GREEN ]
		 psrlq mm1, 32; // mm1 = [ ___ ___ | ___BLUE]

		psllq mm0, 16; // mm0 = [ ____ ____ | GREEN____ ]
		 por mm1, mm3;	// mm1 = [ ___ RED | ___ BLUE ]

		por mm0, mm1;  // mm0 = [ ___ RED | GREEN BLUE ] ; // almost done!
		 pxor mm2, mm2;// clear mm2

		//the pack operation automatically clips the pixel values to 0-255
		packuswb mm0, mm2; // mm0 = [ __ __ | _R GB ]; // final data
		 movq mm1, mm5;  // reload mm0 with Y[_3_2_1_0]
	
	// done with pixel #3, now store @ fbout[]
		movq mm2, mm6;	 // reload mm2 with V[_3_2_1_0]
		 psrlq mm1, 48;	// position mm1 @ pixel3 U[ _ _ _ 3 ]

		movd dword ptr [ edx + 8 ], mm0;	// store 3rd-pixel to fbout[]
		 psrlq mm2, 48;	// position mm2 @ pixel3 V[ _ _ _ 3 ]

		movq mm0, mm4;	 // reload mm0 with Y[_3_2_1_0]
 		 pxor mm7, mm7; // clear mm7

		psrlq mm0, 48;	// position mm0 @ pixel3 Y[ _ _ _ 3 ]

	// done storing pixel #3, begin pixel #4 processing
		 punpcklwd mm0, mm7;	// mm0 = [ __Y1 __Y0 ]

		pand mm1, [pxmask000F]; // mm1 = [ __ __ __ U0 ];
		 punpckldq mm0, mm0;	// mm0 = [ __Y0 __Y0 ];

		pand mm2, [pxmask000F]; // mm2 = [ __ __ __ V0 ];
		 psllq mm1, 32;		// shift u_src[] , mm1 = [ __ U0 __ __ ];

		por mm1, mm2;		// mm0 = [ Y0 __| Y0 V0 ]
		 psllq mm0, 16;	// mm0 = [ Y0__ Y0__ ]

		movq mm3, [yuvRP1GP1]; // mm3 = [ cy crv | cy cgu ] multipliers
		 por mm0, mm1;		// mm0 = [ Y0 U0| Y0 V0 ] READY DATA!

		movq mm1, mm0;	// copy data, mm1 = [  Y0 U0|Y0 V0 ] READY DATA!
		 psrlq mm0, 32;	// mm0 = [ __ __|Y0 U0]

		movq mm2, [rndadjust];	// mm2 = (round adjustment)
		 punpckldq mm0, mm1;	// mm0 = [ Y0 V0| Y0 U0 ]
		
		pmaddwd mm0, mm3;	// compute 1ST result
//		 punpckhdq mm1, mm1;	// mm1 = [ Y0 U0 | Y0 U0 ]

		pmaddwd mm1, [yuvBP1GP2];	// compute 2nd result
		 ;// slot

		;// result 1 = [ PIXEL RED | pPIXEL GREEN]
		;// result 2 = [ PIXEL BLUE| pPIXEL GREEN]

		movq mm7, [pxmask0F00 ]; // mm7 = [ 00 FF | 00 00 ]
		 paddd mm0, mm2;	// mm0 = (1st-result) + (round adjustment)
		 
		movq mm3, mm0;	// copy mm0, mm3 = (1st-result) + (round adjustment)
		 paddd mm1, mm2; // mm1 = (2nd-result) + (round adjustment)

		psrad mm3, RSCALE; // mm3 = [ PIXEL_RED(scaled to 8bit) | garbage ]
		 paddd mm0, mm1; // mm0 = [ garbage | PIXEL GREEN ]

		pand mm3, mm7; // mm3= [ ___ RED | ___ ___ ]
		 psrad mm1, RSCALE; // mm1 = [ PIXEL_BLUE(scaled to 8bit) | garbage ]

		pand mm1, mm7;  // mm1= [ ___ BLUE| ___ ___ ]
		 psrad mm0, RSCALE; // mm0 = [ garbage | pixel_GREEN(scaled to 8bit) ]

		pand mm0, [ pxmask000F]; // mm0 = [ ____ ____ | ____GREEN ]
		 psrlq mm1, 32; // mm1 = [ ___ ___ | ___BLUE]

		psllq mm0, 16; // mm0 = [ ____ ____ | GREEN____ ]
		 por mm1, mm3;	// mm1 = [ ___ RED | ___ BLUE ]

		por mm0, mm1;  // mm0 = [ ___ RED | GREEN BLUE ] ; // almost done!
		 pxor mm2, mm2;// clear mm2

		//the pack operation automatically clips the pixel values to 0-255
		packuswb mm0, mm2; // mm0 = [ __ __ | _R GB ]; // final data
		 add esi, 0x04;	// x = x+4;
	
	// done with pixel #4, now store to fbout[]
		movd dword ptr [ edx + 12 ], mm0;	// store 3rd-quad to fbout[]
		 add edx, 16;	// fbout += 12;  advance 4 pixels (16 bytes)

	// that's it, we've written 4 RGB32 pixels (16-bytes) !
		cmp esi, [dest_w]; // compare ( x <> dest_w )
		 jl lp_yuvtorgb;	// end for ( x = 0; x < dest_w; x += 4);

	sub eax, [srcW];	// y_src -= 1 row
	 sub edi, 0x01;	// y = y -1;
	sub ebx, [srcW];	// y_src -= 1 row
	 mov esi, 0x00;	// x = 0;
	sub ecx, [srcW];	// y_src -= 1 row
	 cmp edi, 0x00; // compare ( y <> 0 )

	jg lp_yuvtorgb;	// end for ( y = dest_w; y > 0; --y )

	emms;

	} // end __asm

/*  the inner loop of the MMX code is equivalent to this inner loop
    for (i=0; i<dest_w; i+=4)
	{
		// store in temporary display buffer 
		// calculate address of pixel(x,y) in *framebuffer 

      { // process 4 output RGB24 pixels at once 
		y = 38155 * ((y_src[ src_addr + i ] - 16) << 1 ); // (255/219)*65536 
		u = (u_src[ src_addr + i ]- 128) << 3;
		v = (v_src[ src_addr + i ]- 128) << 3;

		r = Clip[(y + crv*v + 32768)>>16];
		g = Clip[(y - cgu*u - cgv*v + 32768)>>16];
		b = Clip[(y + cbu*u + 32768)>>16];

			// proper order for BMP RGB24 
		fbout[ dest_addr + 4*i    ] = b;
		fbout[ dest_addr + 4*i + 1] = g;
		fbout[ dest_addr + 4*i + 2] = r;
		
	} // endfor i 
	*/
} // end function y444rgb32()  [ MMX version ]
