/**
 * $Id:$
 * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
 *
 * The contents of this file may be used under the terms of either the GNU
 * General Public License Version 2 or later (the "GPL", see
 * http://www.gnu.org/licenses/gpl.html ), or the Blender License 1.0 or
 * later (the "BL", see http://www.blender.org/BL/ ) which has to be
 * bought from the Blender Foundation to become active, in which case the
 * above mentioned GPL option does not apply.
 *
 * The Original Code is Copyright (C) 2002 by NaN Holding BV.
 * All rights reserved.
 *
 * The Original Code is: all of this file.
 *
 * Contributor(s): none yet.
 *
 * ***** END GPL/BL DUAL LICENSE BLOCK *****
 */

#include "imbuf.h"

#include "xa_mpg.h"

typedef struct Square
{
	void	*next, *prev;
	int		qscale, rlsize;
	
	float	* qtab;

	float	in[8][8];
	float	dct[8][8];
	float	rdct[8][8];
	float	out[8][8];
	
	short	quant[64];
	ushort	runlevel[65];
	char	is_last;
	char	is_c;
}Square;

print_square(Square * square)
{
	int x, y, i;
	
	i = 0;
	
	for (x = 0; x < 8 ; x++) {
		for (y = 0; y < 8 ; y++) {
			printf("%6d ", square->quant[i]);
			i++;
		}
		printf("\n");
	}
	printf("\n");
	printf("\n");
}


float trans_coef[8][8];

float mdec_ytab[64] =
{
	 2, 16, 19, 22, 26, 27, 29, 34, 
	16, 16, 22, 24, 27, 29, 34, 37, 
	19, 22, 26, 27, 29, 34, 34, 38, 
	22, 22, 26, 27, 29, 34, 37, 40, 
	22, 26, 27, 29, 32, 35, 40, 48, 
	26, 27, 29, 32, 35, 40, 48, 58, 
	26, 27, 29, 34, 38, 46, 56, 69, 
	27, 29, 35, 38, 46, 56, 69, 83
};

float mdec_ctab[64] =
{
	 2, 16, 16, 16, 16, 16, 16, 16, 
	16, 16, 16, 16, 16, 16, 16, 16, 
	16, 16, 16, 16, 16, 16, 16, 16, 
	16, 16, 16, 16, 16, 16, 16, 16, 
	16, 16, 16, 16, 16, 16, 16, 16, 
	16, 16, 16, 16, 16, 16, 16, 16, 
	16, 16, 16, 16, 16, 16, 16, 16, 
	16, 16, 16, 16, 16, 16, 16, 16, 
};


int mdec_zscan[64] = 
{
	 0,  1,  8, 16,  9,  2,  3, 10, 
	17, 24, 32, 25, 18, 11,  4,  5, 
	12, 19, 26, 33, 40, 48, 41, 34, 
	27, 20, 13,  6,  7, 14, 21, 28, 
	35, 42, 49, 56, 57, 50, 43, 36, 
	29, 22, 15, 23, 30, 37, 44, 51, 
	58, 59, 52, 45, 38, 31, 39, 46, 
	53, 60, 61, 54, 47, 55, 62, 63
};


#define RUN_SHIFT 10
#define LEVEL_MASK ((1 << RUN_SHIFT) -1)
#define RL_NOP 0xfe00
#define HUFF_MAXRUN	32
#define HUFF_MAXLEVEL	41
#define DCTSIZE2 64

uchar  *mpg_buff = 0;
int   mpg_bsize = 0;

/* BUFFER reading global vars */
int   mpg_b_bnum;
#ifdef WIN32
DWORD  mpg_b_bbuf;
#else
unsigned long long  mpg_b_bbuf;
#endif

/*******
 *
 */
#define MPG_INIT_BBUF(buff, bsize) \
{ mpg_buff = buff; mpg_bsize = bsize; \
  mpg_b_bnum = 0; mpg_b_bbuf = 0; \
}

/*******
 *
 */
#ifdef WIN32
#define MPG_BIT_MASK(s) ((1L << (s)) - 1)
#else
#define MPG_BIT_MASK(s) ((1ll << (s)) - 1)
#endif

/*******
 *
 */
#define MPG_GET_BBITS(num, result) \
{ while(mpg_b_bnum < (num)) { mpg_b_bnum += 8; mpg_bsize--; \
		mpg_b_bbuf = (*mpg_buff++) | (mpg_b_bbuf << 8); } \
  mpg_b_bnum -= (num); \
  (result) = ((mpg_b_bbuf >> mpg_b_bnum) & MPG_BIT_MASK(num)); \
}

#define MPG_NXT_BBITS(num, result) \
{ while(mpg_b_bnum < (num)) { mpg_b_bnum += 8; mpg_bsize--; \
		mpg_b_bbuf = (*mpg_buff++) | (mpg_b_bbuf << 8); } \
  result = (mpg_b_bbuf >> (mpg_b_bnum - num)) & MPG_BIT_MASK(num); \
}

#define MPG_FLUSH_BBITS(num) \
{ while(mpg_b_bnum < (num)) { mpg_b_bnum += 8; mpg_bsize--; \
		mpg_b_bbuf = (*mpg_buff++) | (mpg_b_bbuf << 8); } \
  mpg_b_bnum -= (num); \
}


/**************** HUFFMAN TABLES AND INIT ******************************/

#define MB_ESCAPE 35
#define MB_STUFFING 34


/* Code for unbound values in decoding tables */

#define RUN_MASK_XA		0xfc00
#define LEVEL_MASK_XA	0x03f0
#define NUM_MASK_XA		0x000f
#define RUN_SHIFT_XA	10
#define LEVEL_SHIFT_XA	4
#define END_OF_BLOCK	0x3e
#define DCT_ERROR		0x3f
#define ESCAPE			0x3d


/*
 *--------------------------------------------------------------
 *
 * decodedctcoeff --
 *
 *	Huffman Decoder for dct_coeff_first and dct_coeff_next;
 *      locations where the results of decoding: run and level, are to
 *      be placed and also the type of DCT coefficients, either
 *      dct_coeff_first or dct_coeff_next, are being passed as argument.
 *      
 *      The decoder first examines the next 8 bits in the input stream,
 *      and perform according to the following cases:
 *      
 *      '0000 0000' - examine 8 more bits (i.e. 16 bits total) and
 *                    perform a table lookup on dct_coeff_tbl_0.
 *                    One more bit is then examined to determine the sign
 *                    of level.
 *
 *      '0000 0001' - examine 4 more bits (i.e. 12 bits total) and 
 *                    perform a table lookup on dct_coeff_tbl_1.
 *                    One more bit is then examined to determine the sign
 *                    of level.
 *      
 *      '0000 0010' - examine 2 more bits (i.e. 10 bits total) and
 *                    perform a table lookup on dct_coeff_tbl_2.
 *                    One more bit is then examined to determine the sign
 *                    of level.
 *
 *      '0000 0011' - examine 2 more bits (i.e. 10 bits total) and 
 *                    perform a table lookup on dct_coeff_tbl_3.
 *                    One more bit is then examined to determine the sign
 *                    of level.
 *
 *      otherwise   - perform a table lookup on dct_coeff_tbl. If the
 *                    value of run is not ESCAPE, extract one more bit
 *                    to determine the sign of level; otherwise 6 more
 *                    bits will be extracted to obtain the actual value 
 *                    of run , and then 10 bits to get the value of level.
 *                    
 *      
 *
 * Results:
 *	The decoded values of run and level or ERROR for unbound values
 *      are placed in the locations specified.
 *
 * Side effects:
 *	Bit stream is irreversibly parsed.
 *
 *--------------------------------------------------------------
 */
static void decodedctcoeff(dct_coeff_tbl, run, level)
ushort *dct_coeff_tbl;
uint *run;
int *level;
{
	uint idx, value, f;
	int temp;
	
	MPG_NXT_BBITS(8,idx);

	if (idx > 3)
	{
		value = dct_coeff_tbl[idx];
		*run = (value & RUN_MASK_XA) >> RUN_SHIFT_XA;
		if (*run == END_OF_BLOCK) {
			*level = END_OF_BLOCK;
		} else {
			f = (value & NUM_MASK_XA) + 1;
			MPG_FLUSH_BBITS(f);

			if (*run != ESCAPE)
			{
				uint t;
				*level = (value & LEVEL_MASK_XA) >> LEVEL_SHIFT_XA;
				MPG_GET_BBITS(1,t);
				if (t) *level = - *level;
			}
			else	/* *run == ESCAPE */
			{
				/* non-mpeg-standard */

				MPG_GET_BBITS(16,temp);  /* 6 are run, 10 are part of level */
				*run = temp >> 10;		 /*  1st 6 bits are run */
				*level = (temp << 22) >> 22;
			}
		}
	} else {
		uint t;
		if (idx == 2)
		{
			MPG_NXT_BBITS(10,idx);
			value = dct_coeff_tbl_2[idx & 3];
		}
		else if (idx == 3)
		{
			MPG_NXT_BBITS(10,idx);
			value = dct_coeff_tbl_3[idx & 3];
		}
		else if (idx)	/* idx == 1 */
		{
			MPG_NXT_BBITS(12,idx);
			value = dct_coeff_tbl_1[idx & 15];
		}
		else /* idx == 0 */
		{
			MPG_NXT_BBITS(16,idx);
			value = dct_coeff_tbl_0[idx & 255];
		}
		*run = (value & RUN_MASK_XA) >> RUN_SHIFT_XA;
		*level = (value & LEVEL_MASK_XA) >> LEVEL_SHIFT_XA;

		f = (value & NUM_MASK_XA) + 1;
		MPG_FLUSH_BBITS(f);
		MPG_GET_BBITS(1,t);
		if (t) *level = -*level;
	}
}

void huffparse(Square * square)
{
	short dcval;
	int index, tmp;
	int run, level;

	/* read DCvalue */

	for (index = 1; index < DCTSIZE2; index++) square->quant[index] = 0;

	MPG_GET_BBITS(10, dcval);
	dcval <<= 6;
	dcval >>= 6;
	
	square->quant[0] = dcval;
	
	index = 0;

	while( index < DCTSIZE2 )
	{
		decodedctcoeff(dct_coeff_next, &run, &level);
		if (run == END_OF_BLOCK) break;

		index += (run + 1);
		
		square->quant[index] = level;
	}
	
	MPG_GET_BBITS(2, tmp); /* End of block bits */
	if (tmp != 2) printf("Parse Error: %d index=%d run=%d level=%d\n", tmp, index, run, level);
	
}


void unquant(Square * square)
{
	float * rdct, qscale, *qtab;
	short * quant;
	int i, j;
	
	quant = &square->quant[0];
	rdct = &square->rdct[0][0];
	qtab = square->qtab;
	
	qscale = square->qscale / 8.0;
	
	rdct[0] = quant[0] * qtab[0];

	for (i = 1; i < 64; i++) {
		j = mdec_zscan[i];
		rdct[j] = quant[i] * qtab[j] * qscale;
	}
}


void init_dct()
{
	int i, j;
	float s;

	for (i=0; i<8; i++)
	{
		s = (i==0) ? sqrt(0.125) : 0.5;

		for (j=0; j<8; j++)
			trans_coef[i][j] = s * cos((M_PI/8.0)*i*(j+0.5));
	}
}


void rev_dct(Square * square)
{
	int i, j, k;
	float s;
	float tmp[64];
	static init_done = FALSE;
	
	if (init_done == FALSE) init_dct();
	init_done = TRUE;
	
	for (i=0; i<8; i++)
		for (j=0; j<8; j++)
		{
			s = 0.0;

			for (k=0; k<8; k++)
				s += trans_coef[k][j] * square->rdct[i][k];

			tmp[8*i+j] = s;
		}

	for (i=0; i<8; i++)
		for (j=0; j<8; j++)
		{
			s = 0.0;

			for (k=0; k<8; k++)
				s += trans_coef[k][i] * tmp[8*k+j];

			square->out[i][j] = s;
		}
}

void square2ibuf(Square * square, ImBuf * ibuf, int x, int y, int c)
{
	int i, j;
	uchar * rect;
	float * out, val;
	int overfl = 0;
	
	if (square == 0) return;
	
	rect = (uchar *) (ibuf->rect + x + y * ibuf->x);
	rect += c;
	
	out = &square->out[0][0];
	
	for (i = 0; i < 8; i++) {
		for (j = 0; j < 32; j += 4) {
			val = *out++ + 128.5;
			if (val < 0.0) {
				/*overfl++;*/
				val = 0.0;
			} else if (val > 255.0) {
				val = 255.0;
				/*overfl++;*/
			}
			
			rect[j] = val;
		}
		rect += 4 * ibuf->x;
	}
	
/*
	if (overfl > 32) {
		printf("mdec overfl %d\n", overfl);
		print_square(square);
	}
*/
}

void Rev_Square(Square * square, ImBuf * ibuf, int x, int y, int c)
{
	float tmp[64], * rdct;
	int i, t;
	
	huffparse(square);
	unquant(square);
	rev_dct(square);
	square2ibuf(square, ibuf, x, y, c);
}

void huffdecompress(ImBuf * ibuf, char * mdec, int size, int qscale)
{
	char * buf, *_buf;
	int i, data, x, y;
	Square * square;
	ImBuf * hbuf;
	uchar * src, * dst;
	
	buf = _buf = callocN(size + 4, "huff_compress");
	
	for(i = size; i > 0; i -= 4) {
		*buf++ = mdec[1];
		*buf++ = mdec[0];
		*buf++ = mdec[3];
		*buf++ = mdec[2];
		mdec += 4;	
	}
		
	square = NEW(Square);
	square->qscale = qscale;
	
	MPG_INIT_BBUF((uchar *) _buf, size);
	
	hbuf = allocImBuf(ibuf->x / 2, ibuf->y / 2, 24,  IB_rect, 0);
	
	for (x = 0; x < hbuf->x; x += 8) {
		for (y = 0; y < hbuf->y; y += 8) {
			square->qtab = mdec_ctab;
			Rev_Square(square, hbuf, x, y, 3);
			Rev_Square(square, hbuf, x, y, 1);
			
			square->qtab = mdec_ytab;
			Rev_Square(square, ibuf, 2 * x,     2 * y    , 2);
			Rev_Square(square, ibuf, 2 * x + 8, 2 * y    , 2);
			Rev_Square(square, ibuf, 2 * x,     2 * y + 8, 2);
			Rev_Square(square, ibuf, 2 * x + 8, 2 * y + 8, 2);
		}
	}
	
	/* wat staat er nu nog in de file ???? */
	
	i = (mpg_bsize * 8) + mpg_b_bnum;
	MPG_NXT_BBITS(32, data);
	
	if (data != 0x7fc00000) printf("MDEC PARSE ERROR: still %d bits available: %08x\n", i, data);
	
	dst = (uchar *) ibuf->rect;

	for (y = 0; y < ibuf->y; y++) {
		src = (uchar *) hbuf->rect;
		src += (y >> 1) * hbuf->x * 4;

		for (x = hbuf->x; x > 0; x--) {
			dst[5] = dst[1] = src[1];
			dst[7] = dst[3] = src[3];
			src += 4;
			dst += 8;
		}
	}

	freeImBuf(hbuf);

	freeN(_buf);
	freeN(square);
}