/*
 macam - webcam app and QuickTime driver component
 Copyright (C) 2002 Matthias Krauss (macam@matthias-krauss.de)

 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
 $Id: yuv2rgbCPIA422.c,v 1.2 2006/03/03 18:32:36 hxr Exp $
*/

/*

 This file contains just a raw function body and is intended to be #included from other files, such as yuv2rgb.c

 The function prototype has to be:

 void <whatever>(int width, int height, unsigned char *src, unsigned char *dst, long srcRowExtra, long dstRowExtra);

 */

long x,y;					//loop counters
    long y1,y2,y3,y4;				//The y components in yuv
    long u1,u1g,u1b,u2,u2g,u2b;			//The raw u components and the u differences
    long v1,v1r,v1g,v2,v2r,v2g;			//The raw v components and the v differences
    long r1,g1,b1,r2,g2,b2,r3,g3,b3,r4,g4,b4;	//Destination rgb
    long dstRowBytes;				//EXCLUDING the extra part, just the raw data length per row
    unsigned long ul1,ul2,ul3,ul4;	 	//Temp vars to access memory
#ifdef YUV2RGB_ALPHA
    short bpp=4;
#else
    short bpp=3;
#pragma unused(ul4)
#endif
    width/=4;					//We work in 4 x 1 blocks
    dstRowBytes=4*bpp*width;
#ifdef YUV2RGB_FLIP
    dstRowExtra+=2*dstRowBytes;			//From beginning to end of next line
#endif
    for (y=height;y;y--) {
        for (x=width;x;x--) {
//Read from source buffer
            ul1=CFSwapInt32HostToBig(*((unsigned  long*)(src))); src+=4;	//Read yuyv in line 1
            ul2=CFSwapInt32HostToBig(*((unsigned  long*)(src))); src+=4;	//Read yuyv in line 1
//Extract yuv pixel data
            y1 =(ul1&0xff000000)>>16;
            u1 =((ul1&0x00ff0000)>>16)-128;
            y2 =(ul1&0x0000ff00);
            v1 =(ul1&0x000000ff)-128;
            y3 =(ul2&0xff000000)>>16;
            u2 =((ul2&0x00ff0000)>>16)-128;
            y4 =(ul2&0x0000ff00);
            v2 =(ul2&0x000000ff)-128;
            //convert yuv to rgb: calculate difference coefficients
            u1g =u1*88;
            u1b =u1*454;
            v1r =v1*359;
            v1g =v1*183;
            u2g =u2*88;
            u2b =u2*454;
            v2r =v2*359;
            v2g =v2*183;
            //convert yuv to rgb: assemble rgb
            r1=(y1+v1r)/256;
            g1=(y1-u1g-v1g)/256;
            b1=(y1+u1b)/256;
            r2=(y2+v1r)/256;
            g2=(y2-u1g-v1g)/256;
            b2=(y2+u1b)/256;
            r3=(y3+v2r)/256;
            g3=(y3-u2g-v2g)/256;
            b3=(y3+u2b)/256;
            r4=(y4+v2r)/256;
            g4=(y4-u2g-v2g)/256;
            b4=(y4+u2b)/256;
            //convert yuv to rgb: check value bounds
            r1=CLAMP(r1,0,255);
            g1=CLAMP(g1,0,255);
            b1=CLAMP(b1,0,255);
            r2=CLAMP(r2,0,255);
            g2=CLAMP(g2,0,255);
            b2=CLAMP(b2,0,255);
            r3=CLAMP(r3,0,255);
            g3=CLAMP(g3,0,255);
            b3=CLAMP(b3,0,255);
            r4=CLAMP(r4,0,255);
            g4=CLAMP(g4,0,255);
            b4=CLAMP(b4,0,255);
//Assemble longs from rgb data
#ifndef YUV2RGB_ALPHA
#ifdef YUV2RGB_FLIP
//3bpp, flipped assembly
            ul3=(((unsigned long)r4)<<24)
                |(((unsigned long)g4)<<16)
                |(((unsigned long)b4)<<8)
                |(((unsigned long)r3));
            ul2=(((unsigned long)g3)<<24)
                |(((unsigned long)b3)<<16)
                |(((unsigned long)r2)<<8)
                |(((unsigned long)g2));
            ul1=(((unsigned long)b2)<<24)
                |(((unsigned long)r1)<<16)
                |(((unsigned long)g1)<<8)
                |(((unsigned long)b1));
#else
//3bpp, unflipped assembly
            ul1=(((unsigned long)r1)<<24)
                |(((unsigned long)g1)<<16)
                |(((unsigned long)b1)<<8)
                |(((unsigned long)r2));
            ul2=(((unsigned long)g2)<<24)
                |(((unsigned long)b2)<<16)
                |(((unsigned long)r3)<<8)
                |(((unsigned long)g3));
            ul3=(((unsigned long)b3)<<24)
                |(((unsigned long)r4)<<16)
                |(((unsigned long)g4)<<8)
                |(((unsigned long)b4));
#endif
#else
//4bpp assembly - no matter if flipped or unflipped
            ul1=0xff000000
                |(((unsigned long)r1)<<16)
                |(((unsigned long)g1)<<8)
                |(((unsigned long)b1));
            ul2=0xff000000
                |(((unsigned long)r2)<<16)
                |(((unsigned long)g2)<<8)
                |(((unsigned long)b2));
            ul3=0xff000000
                |(((unsigned long)r3)<<16)
                |(((unsigned long)g3)<<8)
                |(((unsigned long)b3));
            ul4=0xff000000
                |(((unsigned long)r4)<<16)
                |(((unsigned long)g4)<<8)
                |(((unsigned long)b4));
#endif
//Output to destination buffer
#ifdef YUV2RGB_FLIP
#ifdef YUV2RGB_ALPHA
            dst-=16;
            *((unsigned long*)(dst+12))=CFSwapInt32BigToHost(ul1);
            *((unsigned long*)(dst+ 8))=CFSwapInt32BigToHost(ul2);
            *((unsigned long*)(dst+ 4))=CFSwapInt32BigToHost(ul3);
            *((unsigned long*)(dst   ))=CFSwapInt32BigToHost(ul4);
#else	//YUV2RGB_ALPHA
            dst-=12;
            *((unsigned long*)(dst+ 8))=CFSwapInt32BigToHost(ul1);
            *((unsigned long*)(dst+ 4))=CFSwapInt32BigToHost(ul2);
            *((unsigned long*)(dst   ))=CFSwapInt32BigToHost(ul3);
#endif	//YUV2RGB_ALPHA
#else	//YUV2RGB_FLIP
#ifdef YUV2RGB_ALPHA
            *((unsigned long*)(dst))=CFSwapInt32BigToHost(ul1);
            *((unsigned long*)(dst+4))=CFSwapInt32BigToHost(ul2);
            *((unsigned long*)(dst+8))=CFSwapInt32BigToHost(ul3);
            *((unsigned long*)(dst+12))=CFSwapInt32BigToHost(ul4);
            dst+=16;
#else	//YUV2RGB_ALPHA
            *((unsigned long*)(dst))=CFSwapInt32BigToHost(ul1);
            *((unsigned long*)(dst+4))=CFSwapInt32BigToHost(ul2);
            *((unsigned long*)(dst+8))=CFSwapInt32BigToHost(ul3);
            dst+=12;
#endif	//YUV2RGB_ALPHA
#endif	//YUV2RGB_FLIP
        }
        src+=srcRowExtra;
        dst+=dstRowExtra;
    }
//End of included, preprocessor-customized code