/* ppmtoyuvsplit.c - convert a portable pixmap into 3 raw files:
** - basename.Y : The Luminance chunk at the size of the Image
** - basename.U : The Chrominance chunk U at 1/4
** - basename.V : The Chrominance chunk V at 1/4
** The subsampled U and V values are made by arithmetic mean.
**
** If CCIR601 is defined, the produced YUV triples are scaled again
** to fit into the smaller range of values for this standard.
**
** by A.Beck
** Internet: Andre_Beck@IRS.Inf.TU-Dresden.de
**
** Based on ppmtoyuv.c
**
** Permission to use, copy, modify, and distribute this software and its
** documentation for any purpose and without fee is hereby granted, provided
** that the above copyright notice appear in all copies and that both that
** copyright notice and this permission notice appear in supporting
** documentation.  This software is provided "as is" without express or
** implied warranty.
*/

/* Wether to create YUV in JFIF(JPEG) or CCIR.601(MPEG) scale */
#define CCIR601

/* Wether to use pm_close() or fake it -- don't ask me why */
/* #define ORIGINAL */

/* ALPHA Kludge by Franky */

#ifdef __alpha
#define myLONG int
#else
#define myLONG long
#endif

#include <string.h>
#include "ppm.h"

int
main(argc, argv)
char **argv;
{
        FILE *ifp,*vf,*uf,*yf;
        pixel          *pixelrow1,*pixelrow2;
        register pixel *pP1,*pP2;
        int             rows, cols, format, row;
        register int    col;
        pixval          maxval;
        myLONG u,v,y0,y1,y2,y3,u0,u1,u2,u3,v0,v1,v2,v3;
        unsigned char  *y1buf,*y2buf,*ubuf,*vbuf;
        char            ufname[256],vfname[256],yfname[256];


        ppm_init(&argc, argv);

        if ((argc>3)||(argc<2)) pm_usage("basename [ppmfile]");

        if (argc == 3) ifp = pm_openr(argv[2]);
        else ifp = stdin;

        strcpy(ufname,argv[1]);
        strcpy(vfname,argv[1]);
        strcpy(yfname,argv[1]);

        strcat(ufname,".U");
        strcat(vfname,".V");
        strcat(yfname,".Y");

        uf = fopen(ufname,"wb");
        vf = fopen(vfname,"wb");
        yf = fopen(yfname,"wb");

        if(!(uf && vf && yf)) {
         perror("error opening output files");
         exit(0);
        }
        ppm_readppminit(ifp, &cols, &rows, &maxval, &format);

        if(cols & 1) fprintf(stderr,
                             "%s: Warning: odd columns count, exceed ignored\n",
                             argv[0]);
        if(rows & 1) fprintf(stderr,
                             "%s: Warning: odd rows count, exceed ignored\n",
                             argv[0]);

        pixelrow1 = ((pixel*) pm_allocrow( cols, sizeof(pixel) ));
        pixelrow2 = ((pixel*) pm_allocrow( cols, sizeof(pixel) ));

        y1buf = (unsigned char *) pm_allocrow( cols, 1 );
        y2buf = (unsigned char *) pm_allocrow( cols, 1 );
        ubuf = (unsigned char *) pm_allocrow( cols, 1 );
        vbuf = (unsigned char *) pm_allocrow( cols, 1 );

        for (row = 0; row < (rows & ~1); row += 2) {
                unsigned char *y1ptr,*y2ptr,*uptr,*vptr;

                ppm_readppmrow(ifp, pixelrow1, cols, maxval, format);
                ppm_readppmrow(ifp, pixelrow2, cols, maxval, format);

                pP1 = pixelrow1; pP2 = pixelrow2;
                y1ptr = y1buf; y2ptr = y2buf; vptr = vbuf; uptr = ubuf;

                for (col = 0 ; col < (cols & ~1); col += 2) {
                        pixval r0,g0,b0,r1,g1,b1,r2,g2,b2,r3,g3,b3;

                        /* first pixel */
                        r0 = PPM_GETR(*pP1);
                        g0 = PPM_GETG(*pP1);
                        b0 = PPM_GETB(*pP1);
                        pP1++;
                        /* 2nd pixel */
                        r1 = PPM_GETR(*pP1);
                        g1 = PPM_GETG(*pP1);
                        b1 = PPM_GETB(*pP1);
                        pP1++;
                        /* 3rd pixel */
                        r2 = PPM_GETR(*pP2);
                        g2 = PPM_GETG(*pP2);
                        b2 = PPM_GETB(*pP2);
                        pP2++;
                        /* 4th pixel */
                        r3 = PPM_GETR(*pP2);
                        g3 = PPM_GETG(*pP2);
                        b3 = PPM_GETB(*pP2);
                        pP2++;


/* The JFIF RGB to YUV Matrix for $00010000 = 1.0

[Y]   [19595   38469    7471][R]
[U] = [-11056  -21712  32768][G]
[V]   [32768   -27440  -5328][B]

*/

                        y0 =  19595 * r0 + 38469 * g0 +  7471 * b0;
                        u0 = -11056 * r0 - 21712 * g0 + 32768 * b0;
                        v0 =  32768 * r0 - 27440 * g0 -  5328 * b0;

                        y1 =  19595 * r1 + 38469 * g1 +  7471 * b1;
                        u1 = -11056 * r1 - 21712 * g1 + 32768 * b1;
                        v1 =  32768 * r1 - 27440 * g1 -  5328 * b1;

                        y2 =  19595 * r2 + 38469 * g2 +  7471 * b2;
                        u2 = -11056 * r2 - 21712 * g2 + 32768 * b2;
                        v2 =  32768 * r2 - 27440 * g2 -  5328 * b2;

                        y3 =  19595 * r3 + 38469 * g3 +  7471 * b3;
                        u3 = -11056 * r3 - 21712 * g3 + 32768 * b3;
                        v3 =  32768 * r3 - 27440 * g3 -  5328 * b3;

                        /* mean the chroma for subsampling */

                        u  = (u0+u1+u2+u3)>>2;
                        v  = (v0+v1+v2+v3)>>2;

#ifdef CCIR601

                        y0 = (y0 * 219)/255 + 1048576;
                        y1 = (y1 * 219)/255 + 1048576;
                        y2 = (y2 * 219)/255 + 1048576;
                        y3 = (y3 * 219)/255 + 1048576;

                        u  = (u * 224)/255 ;
                        v  = (v * 224)/255 ;
#endif


                        *y1ptr++  = (y0 >> 16) ;
                        *y1ptr++  = (y1 >> 16) ;
                        *y2ptr++  = (y2 >> 16) ;
                        *y2ptr++  = (y3 >> 16) ;


                        *uptr++   = (u >> 16)+128 ;
                        *vptr++   = (v >> 16)+128 ;

                }
                fwrite(y1buf, (cols & ~1), 1, yf);
                fwrite(y2buf, (cols & ~1), 1, yf);
                fwrite(ubuf, cols/2, 1, uf);
                fwrite(vbuf, cols/2, 1, vf);
        }

/* I dunno why pm_close sees an error... get rid of it */

#ifdef ORIGINAL
        pm_close(ifp);
#else
        if(ifp != stdin) fclose(ifp);
#endif
        fclose(yf);
        fclose(uf);
        fclose(vf);
        exit(0);
}
