/*==============*
 * HEADER FILES *
 *==============*/
#include <stdio.h>


typedef unsigned char uint8;

#define CHOP(x)	    ((x < 0) ? 0 : ((x > 255) ? 255 : x))


uint8 **orig_y, **orig_cb, **orig_cr;
uint8 **red, **green, **blue;
int	width = 352;
int	height = 240;

void YUVtoPPM(void);
void	WritePPM(FILE *fpointer);

void ReadYUV();
void AllocYCC();


void	main(int argc, char **argv)
{
    FILE *fpointer;
    char command[256];

    AllocYCC();

    fprintf(stdout, "Reading:  %s\n", argv[1]);
    fpointer = fopen(argv[1], "r");
    ReadYUV(fpointer);
    fclose(fpointer);

    fprintf(stdout, "Converting to PPM\n");
    YUVtoPPM();

    fprintf(stdout, "Writing PPM\n");
    fpointer = fopen("/tmp/foobar", "w");
    WritePPM(fpointer);
    fclose(fpointer);

    fprintf(stdout, "Converting to JPEG %s\n", argv[2]);
    sprintf(command, "cjpeg /tmp/foobar > %s", argv[2]);
    system(command);
}


void	WritePPM(FILE *fpointer)
{
    register int y, x;

    /* magic number */
    fprintf(fpointer, "P6\n");

    /* width, height */
    fprintf(fpointer, "%d %d\n", width, height);

    /* max value */
    fprintf(fpointer, "255\n");

    for ( y = 0; y < height; y++ )
	for ( x = 0; x < width; x++ )
	{
	    fwrite(&red[y][x], 1, 1, fpointer);
	    fwrite(&green[y][x], 1, 1, fpointer);
	    fwrite(&blue[y][x], 1, 1, fpointer);
	}
}


void YUVtoPPM(void)
{
    char    yName[256], uName[256], vName[256], oName[256];
    FILE    *yFile, *uFile, *vFile;
    unsigned char    yData[10];
    unsigned char    vData[2], uData[2];
    long   tempR, tempG, tempB;
    int	    r, g, b;
    register int index;
    int	    **Y, **U, **V;
    int	    x, y;

    /* * first, allocate tons of memory */

    Y = (int **) malloc(sizeof(int *) * height);
    for (y = 0; y < height; y++) {
      Y[y] = (int *) malloc(sizeof(int) * width);
    }

    U = (int **) malloc(sizeof(int *) * height / 2);
    for (y = 0; y < height / 2; y++) {
	U[y] = (int *) malloc(sizeof(int) * width / 2);
    }

    V = (int **) malloc(sizeof(int *) * height / 2);
    for (y = 0; y < height / 2; y++) {
	V[y] = (int *) malloc(sizeof(int) * width / 2);
    }

	for ( y = 0; y < height/2; y ++ )
	    for ( x = 0; x < width/2; x ++ )
	    {
		U[y][x] = orig_cb[y][x] - 128;
		V[y][x] = orig_cr[y][x] - 128;
	    }

	for ( y = 0; y < height; y ++ )
	    for ( x = 0; x < width; x ++ )
	    {
		Y[y][x] = orig_y[y][x] - 16;
	    }

    for ( y = 0; y < height; y++ )
	for ( x = 0; x < width; x++ )
	{
	    /* look at yuvtoppm source for explanation */

	    tempR = 104635*V[y/2][x/2];
	    tempG = -25690*U[y/2][x/2] + -53294 * V[y/2][x/2];
            tempB = 132278*U[y/2][x/2];

	    tempR += (Y[y][x]*76310);
	    tempG += (Y[y][x]*76310);
	    tempB += (Y[y][x]*76310);
	    
	    r = CHOP((int)(tempR >> 16));
	    g = CHOP((int)(tempG >> 16));
	    b = CHOP((int)(tempB >> 16));

	    red[y][x] = r;  green[y][x] = g;	blue[y][x] = b;
	}
}


/*=====================*
 * EXPORTED PROCEDURES *
 *=====================*/

void ReadYUV(fpointer)
     FILE *fpointer;
{
    register int y;

    for (y = 0; y < height; y++)			/* Y */
	fread(orig_y[y], 1, width, fpointer);

    for (y = 0; y < height / 2; y++)			/* U */
	fread(orig_cb[y], 1, width / 2, fpointer);

    for (y = 0; y < height / 2; y++)			/* V */
	fread(orig_cr[y], 1, width / 2, fpointer);
}


void AllocYCC()
{
    register int y;

    /*
     * first, allocate tons of memory
     */
    orig_y = (uint8 **) malloc(sizeof(uint8 *) * height);
    for (y = 0; y < height; y++) {
	orig_y[y] = (uint8 *) malloc(sizeof(uint8) * width);
    }

    orig_cr = (uint8 **) malloc(sizeof(uint8 *) * height / 2);
    for (y = 0; y < height / 2; y++) {
	orig_cr[y] = (uint8 *) malloc(sizeof(uint8) * width / 2);
    }

    orig_cb = (uint8 **) malloc(sizeof(uint8 *) * height / 2);
    for (y = 0; y < height / 2; y++) {
	orig_cb[y] = (uint8 *) malloc(sizeof(uint8) * width / 2);
    }

    /* * first, allocate tons of memory */

    red = (uint8 **) malloc(sizeof(uint8 *) * height);
    for (y = 0; y < height; y++) {
      red[y] = (uint8 *) malloc(sizeof(uint8) * width);
    }

    green = (uint8 **) malloc(sizeof(uint8 *) * height);
    for (y = 0; y < height; y++) {
	green[y] = (uint8 *) malloc(sizeof(uint8) * width);
    }

    blue = (uint8 **) malloc(sizeof(uint8 *) * height);
    for (y = 0; y < height; y++) {
	blue[y] = (uint8 *) malloc(sizeof(uint8) * width);
    }
}


