view libmpcodecs/vd_huffyuv.c @ 9278:caea8ed36b48

The reason why mplayer crashes (in some cases) when using x11 output and -wid (>0) parameter is this: Mplayer by default creates a colormap using DirectColor visual. If the window given to mplayer uses TrueColor visual there will be an error when mplayer sets the colormap for the window. This patch modifies mplayer to use TrueColor visual if the window given to mplayer uses TrueColor. Another solution is to make sure that the window given to mplayer is created using DirectColor visual if it is supported by the display. Jouni Tulkki <jitulkki@cc.hut.fi>
author arpi
date Tue, 04 Feb 2003 18:31:44 +0000
parents 772d6d27fd66
children
line wrap: on
line source

/*
 *
 * HuffYUV Decoder for Mplayer
 * (c) 2002 Roberto Togni
 *
 * Fourcc: HFYU
 *
 * Original Win32 codec copyright:
 *
 *** Huffyuv v2.1.1, by Ben Rudiak-Gould.
 *** http://www.math.berkeley.edu/~benrg/huffyuv.html
 ***
 *** This file is copyright 2000 Ben Rudiak-Gould, and distributed under
 *** the terms of the GNU General Public License, v2 or later.  See
 *** http://www.gnu.org/copyleft/gpl.html.
 *
 */

#include <stdio.h>
#include <stdlib.h>

#include "config.h"
#include "mp_msg.h"

#include "vd_internal.h"


static vd_info_t info = {
	"HuffYUV Video decoder",
	"huffyuv",
	"Roberto Togni",
	"Roberto Togni, original win32 by Ben Rudiak-Gould http://www.math.berkeley.edu/~benrg/huffyuv.html",
	"native codec"
};

LIBVD_EXTERN(huffyuv)


/*
 * Bitmap types
 */
#define BMPTYPE_YUV -1
#define BMPTYPE_RGB -2
#define BMPTYPE_RGBA -3

/*
 * Compression methods
 */
#define METHOD_LEFT 0
#define METHOD_GRAD 1
#define METHOD_MEDIAN 2
#define DECORR_FLAG 64
#define METHOD_LEFT_DECORR (METHOD_LEFT | DECORR_FLAG)
#define METHOD_GRAD_DECORR (METHOD_GRAD | DECORR_FLAG)
#define METHOD_OLD -2 

#define FOURCC_HFYU mmioFOURCC('H','F','Y','U')

#define HUFFTABLE_CLASSIC_YUV ((unsigned char*) -1)
#define HUFFTABLE_CLASSIC_RGB ((unsigned char*) -2)
#define HUFFTABLE_CLASSIC_YUV_CHROMA ((unsigned char*) -3)


/*
 * Huffman table
 */
typedef struct {
	unsigned char* table_pointers[32];
	unsigned char table_data[129*25];
} DecodeTable;


/*
 * Decoder context
 */
typedef struct {
	// Real image depth
	int bitcount;
	// Prediction method
	int method;
	// Bitmap color type
	int bitmaptype;
	// Interlaced flag
	int interlaced;
	// Huffman tables
	unsigned char decode1_shift[256];
	unsigned char decode2_shift[256];
	unsigned char decode3_shift[256];
	DecodeTable decode1, decode2, decode3;
	// Above line buffers
	unsigned char *abovebuf1, *abovebuf2;
} huffyuv_context_t;


/*
 * Classic Huffman tables
 */
unsigned char classic_shift_luma[] = {
  34,36,35,69,135,232,9,16,10,24,11,23,12,16,13,10,14,8,15,8,
  16,8,17,20,16,10,207,206,205,236,11,8,10,21,9,23,8,8,199,70,
  69,68, 0
};

unsigned char classic_shift_chroma[] = {
  66,36,37,38,39,40,41,75,76,77,110,239,144,81,82,83,84,85,118,183,
  56,57,88,89,56,89,154,57,58,57,26,141,57,56,58,57,58,57,184,119,
  214,245,116,83,82,49,80,79,78,77,44,75,41,40,39,38,37,36,34, 0
};

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

unsigned char classic_add_chroma[256] = {
    3,  1,  2,  2,  2,  2,  3,  3,  7,  5,  7,  5,  8,  6, 11,  9,
    7, 13, 11, 10,  9,  8,  7,  5,  9,  7,  6,  4,  7,  5,  8,  7,
   11,  8, 13, 11, 19, 15, 22, 23, 20, 33, 32, 28, 27, 29, 51, 77,
   43, 45, 76, 81, 46, 82, 75, 55, 56,144, 58, 80, 60, 74,147, 63,
  143, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
   80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 27, 30, 21, 22,
   17, 14,  5,  6,100, 54, 47, 50, 51, 53,106,107,108,109,110,111,
  112,113,114,115,  4,117,118, 92, 94,121,122,  3,124,103,  2,  1,
    0,129,130,131,120,119,126,125,136,137,138,139,140,141,142,134,
  135,132,133,104, 64,101, 62, 57,102, 95, 93, 59, 61, 28, 97, 96,
   52, 49, 48, 29, 32, 25, 24, 46, 23, 98, 45, 44, 43, 20, 42, 41,
   19, 18, 99, 40, 15, 39, 38, 16, 13, 12, 11, 37, 10,  9,  8, 36,
    7,128,127,105,123,116, 35, 34, 33,145, 31, 79, 42,146, 78, 26,
   83, 48, 49, 50, 44, 47, 26, 31, 30, 18, 17, 19, 21, 24, 25, 13,
   14, 16, 17, 18, 20, 21, 12, 14, 15,  9, 10,  6,  9,  6,  5,  8,
    6, 12,  8, 10,  7,  9,  6,  4,  6,  2,  2,  3,  3,  3,  3,  2,
};


/*
 * Internal function prototypes
 */
unsigned char* InitializeDecodeTable(unsigned char* hufftable,
								unsigned char* shift, DecodeTable* decode_table);
unsigned char* InitializeShiftAddTables(unsigned char* hufftable,
								unsigned char* shift, unsigned* add_shifted);
unsigned char* DecompressHuffmanTable(unsigned char* hufftable,
																			unsigned char* dst);
unsigned char huff_decompress(unsigned int* in, unsigned int *pos,
														  DecodeTable *decode_table, unsigned char *decode_shift);




// to set/get/query special features/parameters
static int control(sh_video_t *sh,int cmd,void* arg,...)
{
	switch(cmd) {
		case VDCTRL_QUERY_FORMAT:
			if  (((huffyuv_context_t *)(sh->context))->bitmaptype == BMPTYPE_YUV) {
				if (*((int*)arg) == IMGFMT_YUY2)
					return CONTROL_TRUE;
				else
					return CONTROL_FALSE;
			} else {
				if ((*((int*)arg) == IMGFMT_BGR32) || (*((int*)arg) == IMGFMT_BGR24))
					return CONTROL_TRUE;
				else
					return CONTROL_FALSE;
			}
	}
	return CONTROL_UNKNOWN;
}


/*
 *
 * Init HuffYUV decoder
 *
 */
static int init(sh_video_t *sh)
{
	int vo_ret; // Video output init ret value
	huffyuv_context_t *hc; // Decoder context
	unsigned char *hufftable; // Compressed huffman tables
	BITMAPINFOHEADER *bih = sh->bih;
	
	if ((hc = malloc(sizeof(huffyuv_context_t))) == NULL) {
		mp_msg(MSGT_DECVIDEO, MSGL_ERR, "Can't allocate memory for HuffYUV decoder context\n");
		return 0;
	}

	sh->context = (void *)hc;

	if (bih->biCompression != FOURCC_HFYU) {
		mp_msg(MSGT_DECVIDEO, MSGL_WARN, "[HuffYUV] BITMAPHEADER fourcc != HFYU\n");
		return 0;
	}

	/* Get bitcount */
	hc->bitcount = 0;
	if (bih->biSize > sizeof(BITMAPINFOHEADER)+1)
		hc->bitcount = *((char*)bih + sizeof(BITMAPINFOHEADER) + 1);
	if (hc->bitcount == 0)
		hc->bitcount = bih->biBitCount;

	/* Get bitmap type */
	switch (hc->bitcount & ~7) {
		case 16:
			hc->bitmaptype = BMPTYPE_YUV; // -1
			mp_msg(MSGT_DECVIDEO, MSGL_V, "[HuffYUV] Image type is YUV\n");
			break;
		case 24:
			hc->bitmaptype = BMPTYPE_RGB; // -2
			mp_msg(MSGT_DECVIDEO, MSGL_V, "[HuffYUV] Image type is RGB\n");
			break;
		case 32:
			hc->bitmaptype = BMPTYPE_RGBA; //-3
			mp_msg(MSGT_DECVIDEO, MSGL_V, "[HuffYUV] Image type is RGBA\n");
			break;
		default:
			hc->bitmaptype = 0; // ERR
			mp_msg(MSGT_DECVIDEO, MSGL_WARN, "[HuffYUV] Image type is unknown\n");
	}

	/* Get method */
	switch (bih->biBitCount & 7) {
		case 0:
			if (bih->biSize > sizeof(BITMAPINFOHEADER)) {
				hc->method = *((unsigned char*)bih + sizeof(BITMAPINFOHEADER));
				mp_msg(MSGT_DECVIDEO, MSGL_V, "[HuffYUV] Method stored in extra data\n");
			} else
				hc->method = METHOD_OLD;	// Is it really needed?
			break;
		case 1:
			hc->method = METHOD_LEFT;
			break;
		case 2:
			hc->method = METHOD_LEFT_DECORR;
			break;
		case 3:
			if (hc->bitmaptype == BMPTYPE_YUV) {
				hc->method = METHOD_GRAD;
			} else {
				hc->method = METHOD_GRAD_DECORR;
			}
			break;
		case 4:
			hc->method = METHOD_MEDIAN;
			break;
		default:
			mp_msg(MSGT_DECVIDEO, MSGL_V, "[HuffYUV] Method: fallback to METHOD_OLD\n");
			hc->method = METHOD_OLD;
	}

	/* Print method info */
	switch (hc->method) {
		case METHOD_LEFT:
			mp_msg(MSGT_DECVIDEO, MSGL_V, "[HuffYUV] Method: Predict Left\n");
			break;
		case METHOD_GRAD:
			mp_msg(MSGT_DECVIDEO, MSGL_V, "[HuffYUV] Method: Predict Gradient\n");
			break;
		case METHOD_MEDIAN:
			mp_msg(MSGT_DECVIDEO, MSGL_V, "[HuffYUV] Method: Predict Median\n");
			break;
		case METHOD_LEFT_DECORR:
			mp_msg(MSGT_DECVIDEO, MSGL_V, "[HuffYUV] Method: Predict Left with decorrelation\n");
			break;
		case METHOD_GRAD_DECORR:
			mp_msg(MSGT_DECVIDEO, MSGL_V, "[HuffYUV] Method: Predict Gradient with decorrelation\n");
			break;
		case METHOD_OLD:
			mp_msg(MSGT_DECVIDEO, MSGL_V, "[HuffYUV] Method Old\n");
			break;
		default:
			mp_msg(MSGT_DECVIDEO, MSGL_WARN, "[HuffYUV] Method unknown\n");
	}

	/* Take care of interlaced images */
	hc->interlaced = 0;
	if (bih->biHeight > 288) {
		// Image is interlaced (flag != 0), but we may not care
		hc->interlaced = 1;
		mp_msg(MSGT_DECVIDEO, MSGL_V, "[HuffYUV] Image is interlaced\n");
	}

	/* Allocate buffers */
	hc->abovebuf1 = NULL;
	hc->abovebuf2 = NULL;
	if ((hc->method == METHOD_MEDIAN) || (hc->method == METHOD_GRAD) ||
			(hc->method == METHOD_GRAD_DECORR)) {
		// If inetrlaced flag will be 2
		(hc->interlaced)++;
		mp_msg(MSGT_DECVIDEO, MSGL_V, "[HuffYUV] Allocating above line buffer\n");
		if ((hc->abovebuf1 = malloc(sizeof(char) * 4 * bih->biWidth * hc->interlaced)) == NULL) {
			mp_msg(MSGT_DECVIDEO, MSGL_ERR, "Can't allocate memory for HuffYUV above buffer 1\n");
			return 0;
		}

		if ((hc->abovebuf2 = malloc(sizeof(char) * 4 * bih->biWidth * hc->interlaced)) == NULL) {
			mp_msg(MSGT_DECVIDEO, MSGL_ERR, "Can't allocate memory for HuffYUV above buffer 2\n");
			return 0;
		}
	}

	/* Get compressed Huffman tables */
	if (bih->biSize == sizeof(BITMAPINFOHEADER) /*&& !(bih->biBitCount&7)*/) {
		hufftable = (hc->bitmaptype == BMPTYPE_YUV) ? HUFFTABLE_CLASSIC_YUV : HUFFTABLE_CLASSIC_RGB;
		mp_msg(MSGT_DECVIDEO, MSGL_V, "[HuffYUV] Using classic static Huffman tables\n");
	} else {
		hufftable = (unsigned char*)bih + sizeof(BITMAPINFOHEADER) + ((bih->biBitCount&7) ? 0 : 4);
		mp_msg(MSGT_DECVIDEO, MSGL_V, "[HuffYUV] Using Huffman tables stored in file\n");
	}

	/* Initialize decoder Huffman tables */
	hufftable = InitializeDecodeTable(hufftable, hc->decode1_shift, &(hc->decode1));
	hufftable = InitializeDecodeTable(hufftable, hc->decode2_shift, &(hc->decode2));
	InitializeDecodeTable(hufftable, hc->decode3_shift, &(hc->decode3));

	/*
	 * Initialize video output device
	 */
	switch (hc->bitmaptype) {
		case BMPTYPE_YUV:
			vo_ret = mpcodecs_config_vo(sh,sh->disp_w,sh->disp_h,IMGFMT_YUY2);
			break;
		case BMPTYPE_RGB:
			vo_ret = mpcodecs_config_vo(sh,sh->disp_w,sh->disp_h,IMGFMT_BGR24);
			break;
		case BMPTYPE_RGBA:
			mp_msg(MSGT_DECVIDEO, MSGL_ERR, "[HuffYUV] RGBA not supported yet.\n");
			return 0;
		default:
			mp_msg(MSGT_DECVIDEO, MSGL_ERR, "[HuffYUV] BUG! Unknown bitmaptype in vo config.\n");
			return 0;
	}

	return vo_ret;
}




/*
 *
 * Uninit HuffYUV decoder
 *
 */
static void uninit(sh_video_t *sh)
{
	if (sh->context) {
		if (((huffyuv_context_t*)&sh->context)->abovebuf1)
			free(((huffyuv_context_t*)sh->context)->abovebuf1);
		if (((huffyuv_context_t*)&sh->context)->abovebuf2)
			free(((huffyuv_context_t*)sh->context)->abovebuf2);
		free(sh->context);
	}
}



#define HUFF_DECOMPRESS_YUYV() \
{ \
	y1 = huff_decompress((unsigned int *)encoded, &pos, &(hc->decode1), hc->decode1_shift); \
	u = huff_decompress((unsigned int *)encoded, &pos, &(hc->decode2), hc->decode2_shift); \
	y2 = huff_decompress((unsigned int *)encoded, &pos, &(hc->decode1), hc->decode1_shift); \
	v = huff_decompress((unsigned int *)encoded, &pos, &(hc->decode3), hc->decode3_shift); \
}



#define HUFF_DECOMPRESS_RGB_DECORR() \
{ \
	g = huff_decompress((unsigned int *)encoded, &pos, &(hc->decode2), hc->decode2_shift); \
	b = huff_decompress((unsigned int *)encoded, &pos, &(hc->decode1), hc->decode1_shift); \
	r = huff_decompress((unsigned int *)encoded, &pos, &(hc->decode3), hc->decode3_shift); \
}



#define HUFF_DECOMPRESS_RGB() \
{ \
	b = huff_decompress((unsigned int *)encoded, &pos, &(hc->decode1), hc->decode1_shift); \
	g = huff_decompress((unsigned int *)encoded, &pos, &(hc->decode2), hc->decode2_shift); \
	r = huff_decompress((unsigned int *)encoded, &pos, &(hc->decode3), hc->decode3_shift); \
}



#define MEDIAN(left, above, aboveleft) \
{ \
	if ((mi = (above)) > (left)) { \
		mx = mi; \
		mi = (left); \
	} else \
		mx = (left); \
	tmp = (above) + (left) - (aboveleft); \
	if (tmp < mi) \
		med = mi; \
	else if (tmp > mx) \
		med = mx; \
	else \
		med = tmp; \
}



#define YUV_STORE1ST_ABOVEBUF() \
{ \
	abovebuf[0] = outptr[0] = encoded[0]; \
	abovebuf[1] = left_u = outptr[1] = encoded[1]; \
	abovebuf[2] = left_y = outptr[2] = encoded[2]; \
	abovebuf[3] = left_v = outptr[3] = encoded[3]; \
	pixel_ptr = 4; \
}



#define YUV_STORE1ST() \
{ \
	outptr[0] = encoded[0]; \
	left_u = outptr[1] = encoded[1]; \
	left_y = outptr[2] = encoded[2]; \
	left_v = outptr[3] = encoded[3]; \
	pixel_ptr = 4; \
}



#define RGB_STORE1ST() \
{ \
	pixel_ptr = (height-1)*mpi->stride[0]; \
	left_b = outptr[pixel_ptr++] = encoded[1]; \
	left_g = outptr[pixel_ptr++] = encoded[2]; \
	left_r = outptr[pixel_ptr++] = encoded[3]; \
	pixel_ptr += bgr32; \
}



#define RGB_STORE1ST_ABOVEBUF() \
{ \
	pixel_ptr = (height-1)*mpi->stride[0]; \
	abovebuf[0] = left_b = outptr[pixel_ptr++] = encoded[1]; \
	abovebuf[1] = left_g = outptr[pixel_ptr++] = encoded[2]; \
	abovebuf[2] = left_r = outptr[pixel_ptr++] = encoded[3]; \
	pixel_ptr += bgr32; \
}




#define YUV_PREDLEFT() \
{ \
	outptr[pixel_ptr++] = left_y += y1; \
	outptr[pixel_ptr++] = left_u += u; \
	outptr[pixel_ptr++] = left_y += y2; \
	outptr[pixel_ptr++] = left_v += v; \
}



#define YUV_PREDLEFT_BUF(buf, offs) \
{ \
	(buf)[(offs)] = outptr[pixel_ptr++] = left_y += y1; \
	(buf)[(offs)+1] = outptr[pixel_ptr++] = left_u += u; \
	(buf)[(offs)+2] = outptr[pixel_ptr++] = left_y += y2; \
	(buf)[(offs)+3] = outptr[pixel_ptr++] = left_v += v; \
}



#define YUV_PREDMED() \
{ \
	MEDIAN (left_y, abovebuf[col], abovebuf[col-2]); \
	curbuf[col] = outptr[pixel_ptr++] = left_y = med + y1; \
	MEDIAN (left_u, abovebuf[col+1], abovebuf[col+1-4]); \
	curbuf[col+1] = outptr[pixel_ptr++] = left_u = med + u; \
	MEDIAN (left_y, abovebuf[col+2], abovebuf[col+2-2]); \
	curbuf[col+2] = outptr[pixel_ptr++] = left_y = med + y2; \
	MEDIAN (left_v, abovebuf[col+3], abovebuf[col+3-4]); \
	curbuf[col+3] = outptr[pixel_ptr++] = left_v = med + v; \
}



#define YUV_PREDMED_1ST() \
{ \
	MEDIAN (left_y, abovebuf[0], curbuf[width2*4-2]); \
	curbuf[0] = outptr[pixel_ptr++] = left_y = med + y1; \
	MEDIAN (left_u, abovebuf[1], curbuf[width2*4+1-4]); \
	curbuf[1] = outptr[pixel_ptr++] = left_u = med + u; \
	MEDIAN (left_y, abovebuf[2], abovebuf[0]); \
	curbuf[2] = outptr[pixel_ptr++] = left_y = med + y2; \
	MEDIAN (left_v, abovebuf[3], curbuf[width2*4+3-4]); \
	curbuf[3] = outptr[pixel_ptr++] = left_v = med + v; \
}
	
	
	
#define YUV_PREDGRAD() \
{ \
	curbuf[col] = outptr[pixel_ptr++] = left_y += y1 + abovebuf[col]-abovebuf[col-2]; \
	curbuf[col+1] = outptr[pixel_ptr++] = left_u += u + abovebuf[col+1]-abovebuf[col+1-4]; \
	curbuf[col+2] = outptr[pixel_ptr++] = left_y += y2 + abovebuf[col+2]-abovebuf[col+2-2]; \
	curbuf[col+3] = outptr[pixel_ptr++] = left_v += v + abovebuf[col+3]-abovebuf[col+3-4]; \
}



#define YUV_PREDGRAD_1ST() \
{ \
	curbuf[0] = outptr[pixel_ptr++] = left_y += y1 + abovebuf[0] - curbuf[width2*4-2]; \
	curbuf[1] = outptr[pixel_ptr++] = left_u += u + abovebuf[1] - curbuf[width2*4+1-4]; \
	curbuf[2] = outptr[pixel_ptr++] = left_y += y2 + abovebuf[2] - abovebuf[0]; \
	curbuf[3] = outptr[pixel_ptr++] = left_v += v + abovebuf[3] - curbuf[width2*4+3-4]; \
}



#define RGB_PREDLEFT_DECORR() \
{ \
	outptr[pixel_ptr++] = left_b += b + g; \
	outptr[pixel_ptr++] = left_g += g; \
	outptr[pixel_ptr++] = left_r += r + g; \
	pixel_ptr += bgr32; \
}



#define RGB_PREDLEFT_DECORR_BUF() \
{ \
	abovebuf[col] = outptr[pixel_ptr++] = left_b += b + g; \
	abovebuf[col+1] = outptr[pixel_ptr++] = left_g += g; \
	abovebuf[col+2] = outptr[pixel_ptr++] = left_r += r + g; \
	pixel_ptr += bgr32; \
}


#define RGB_PREDLEFT() \
{ \
	outptr[pixel_ptr++] = left_b += b; \
	outptr[pixel_ptr++] = left_g += g; \
	outptr[pixel_ptr++] = left_r += r; \
	pixel_ptr += bgr32; \
}



#define RGB_PREDGRAD_DECORR() \
{ \
	curbuf[col] = outptr[pixel_ptr++] = left_b += b + g + abovebuf[col]-abovebuf[col-3]; \
	curbuf[col+1] = outptr[pixel_ptr++] = left_g += g + abovebuf[col+1]-abovebuf[col+1-3]; \
	curbuf[col+2] = outptr[pixel_ptr++] = left_r += r + g + abovebuf[col+2]-abovebuf[col+2-3]; \
	pixel_ptr += bgr32; \
}



#define RGB_PREDGRAD_DECORR_1ST() \
{ \
	curbuf[0] = outptr[pixel_ptr++] = left_b += b + g + abovebuf[0] - curbuf[width2*3-3]; \
	curbuf[1] = outptr[pixel_ptr++] = left_g += g + abovebuf[1] - curbuf[width2*3+1-3]; \
	curbuf[2] = outptr[pixel_ptr++] = left_r += r + g + abovebuf[2] - curbuf[width2*3+2-3]; \
	pixel_ptr += bgr32; \
}



#define SWAPBUF() \
{ \
	swap = abovebuf; \
	abovebuf = curbuf; \
	curbuf = swap; \
}



/*
 *
 * Decode a HuffYUV frame
 *
 */
static mp_image_t* decode(sh_video_t *sh,void* data,int len,int flags)
{
	mp_image_t* mpi;
	int pixel_ptr;
	unsigned char y1, y2, u, v, r, g, b/*, a*/;
	unsigned char left_y, left_u, left_v, left_r, left_g, left_b;
	unsigned char tmp, mi, mx, med;
	unsigned char *swap;
	int row, col;
	unsigned int pos = 32;
	unsigned char *encoded = (unsigned char *)data;
	huffyuv_context_t *hc = (huffyuv_context_t *) sh->context; // Decoder context
	unsigned char *abovebuf = hc->abovebuf1;
	unsigned char *curbuf = hc->abovebuf2;
	unsigned char *outptr;
	int width = sh->disp_w; // Real image width
	int height = sh->disp_h; // Real image height
	int width2, height2;
	int bgr32;
	int interlaced, oddlines;

	// Skipped frame
	if(len <= 0)
		return NULL;

	/* If image is interlaced and we care about it fix size */
	if (hc->interlaced == 2) {
		width2 = width*2; // Double image width
		height2 = height/2; // Half image height
		oddlines = height%2; // Set if line number is odd
		interlaced = 1; // Used also for row counter computation, must be exactly 1
	} else {
		width2 = width; // Real image width
		height2 = height; // Real image height
		interlaced = 0;  // Flag is 0: no need to deinterlaced image
		oddlines = 0; // Don't care about odd line number if not interlaced
	}


	/* Get output image buffer */
	mpi=mpcodecs_get_image(sh, MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, sh->disp_w, sh->disp_h);
	if (!mpi) {
		mp_msg(MSGT_DECVIDEO, MSGL_ERR, "Can't allocate mpi image for huffyuv codec.\n");
		return NULL;
	}

	outptr = mpi->planes[0]; // Output image pointer

	if (hc->bitmaptype == BMPTYPE_YUV) {
		width >>= 1; // Each cycle stores two pixels
		width2 >>= 1;
		if (hc->method == METHOD_GRAD) {
			/*
			 * YUV predict gradient
			 */
			/* Store 1st pixel */
			YUV_STORE1ST_ABOVEBUF();
			// Decompress 1st row (always stored with left prediction)
			for (col = 1*4; col < width*4; col += 4) {
				HUFF_DECOMPRESS_YUYV();
				YUV_PREDLEFT_BUF (abovebuf, col);
			}
			if (interlaced) {
				pixel_ptr = mpi->stride[0];
				for (col = width*4; col < width*8; col += 4) {
					HUFF_DECOMPRESS_YUYV();
					YUV_PREDLEFT_BUF (abovebuf, col);
				}
			}
			curbuf[width2*4-1] = curbuf[width2*4-2] = curbuf[width2*4-3] = 0;
			for (row = 1; row < height2; row++) {
				pixel_ptr = (interlaced + 1) * row * mpi->stride[0];
				HUFF_DECOMPRESS_YUYV();
				YUV_PREDGRAD_1ST();
				for (col = 1*4; col < width*4; col += 4) {
					HUFF_DECOMPRESS_YUYV();
					YUV_PREDGRAD();
				}
				if (interlaced) {
					pixel_ptr = (2 * row + 1) * mpi->stride[0];
					for (col = width*4; col < width*8; col += 4) {
						HUFF_DECOMPRESS_YUYV();
						YUV_PREDGRAD();
					}
				}
				SWAPBUF();
			}
			if (oddlines) {
				pixel_ptr = 2 * height * mpi->stride[0];
				HUFF_DECOMPRESS_YUYV();
				YUV_PREDGRAD_1ST();
				for (col = 1*4; col < width*4; col += 4) {
					HUFF_DECOMPRESS_YUYV();
					YUV_PREDGRAD();
				}
			}
		} else if (hc->method == METHOD_MEDIAN) {
			/*
			 * YUV predict median
			 */
			/* Store 1st pixel */
			YUV_STORE1ST_ABOVEBUF();
			// Decompress 1st row (always stored with left prediction)
			for (col = 1*4; col < width*4; col += 4) {
				HUFF_DECOMPRESS_YUYV();
				YUV_PREDLEFT_BUF (abovebuf, col);
			}
			if (interlaced) {
				pixel_ptr = mpi->stride[0];
				for (col = width*4; col < width*8; col += 4) {
					HUFF_DECOMPRESS_YUYV();
					YUV_PREDLEFT_BUF (abovebuf, col);
				}
			}
			// Decompress 1st two pixels of 2nd row
			pixel_ptr = mpi->stride[0] * (interlaced + 1);
			HUFF_DECOMPRESS_YUYV();
			YUV_PREDLEFT_BUF (curbuf, 0);
			HUFF_DECOMPRESS_YUYV();
			YUV_PREDLEFT_BUF (curbuf, 4);
			// Complete 2nd row
			for (col = 2*4; col < width*4; col += 4) {
				HUFF_DECOMPRESS_YUYV();
				YUV_PREDMED();
			}
			if (interlaced) {
				pixel_ptr = mpi->stride[0] * 3;
				for (col = width*4; col < width*8; col += 4) {
					HUFF_DECOMPRESS_YUYV();
					YUV_PREDMED();
				}
			}
			SWAPBUF();
			for (row = 2; row < height2; row++) {
				pixel_ptr = (interlaced + 1) * row * mpi->stride[0];
				HUFF_DECOMPRESS_YUYV();
				YUV_PREDMED_1ST();
				for (col = 1*4; col < width*4; col += 4) {
					HUFF_DECOMPRESS_YUYV();
					YUV_PREDMED();
				}
				if (interlaced) {
					pixel_ptr = (2 * row + 1) * mpi->stride[0];
					for (col = width*4; col < width*8; col += 4) {
						HUFF_DECOMPRESS_YUYV();
						YUV_PREDMED();
					}
				}
				SWAPBUF();
			}
			if (oddlines) {
				pixel_ptr = 2 * height2 * mpi->stride[0];
				HUFF_DECOMPRESS_YUYV();
				YUV_PREDMED_1ST();
				for (col = 1*4; col < width*4; col += 4) {
					HUFF_DECOMPRESS_YUYV();
					YUV_PREDMED();
				}
			}
		} else {
			/*
			 * YUV predict left and predict old
			 */
			/* Store 1st pixel */
			YUV_STORE1ST();
			// Decompress 1st row (always stored with left prediction)
			for (col = 1*4; col < width*4; col += 4) {
				HUFF_DECOMPRESS_YUYV();
				YUV_PREDLEFT();
			}
			for (row = 1; row < height; row++) {
				pixel_ptr = row * mpi->stride[0];
				for (col = 0; col < width*4; col += 4) {
					HUFF_DECOMPRESS_YUYV();
					YUV_PREDLEFT();
				}
			}
		}
	} else {
		bgr32 = (mpi->bpp) >> 5; // 1 if bpp = 32, 0 if bpp = 24
		if (hc->method == METHOD_LEFT_DECORR) {
			/*
			 * RGB predict left with decorrelation
			 */
			/* Store 1st pixel */
			RGB_STORE1ST();
			// Decompress 1st row
			for (col = 1; col < width; col ++) {
				HUFF_DECOMPRESS_RGB_DECORR();
				RGB_PREDLEFT_DECORR();
			}
			for (row = 1; row < height; row++) {
				pixel_ptr = (height - row - 1) * mpi->stride[0];
				for (col = 0; col < width; col++) {
					HUFF_DECOMPRESS_RGB_DECORR();
					RGB_PREDLEFT_DECORR();
				}
			}
		} else if (hc->method == METHOD_GRAD_DECORR) {
			/*
			 * RGB predict gradient with decorrelation
			 */
			/* Store 1st pixel */
			RGB_STORE1ST_ABOVEBUF();
			// Decompress 1st row (always stored with left prediction)
			for (col = 1*3; col < width*3; col += 3) {
				HUFF_DECOMPRESS_RGB_DECORR();
				RGB_PREDLEFT_DECORR_BUF();
			}
			if (interlaced) {
				pixel_ptr = (height-2)*mpi->stride[0];
				for (col = width*3; col < width*6; col += 3) {
					HUFF_DECOMPRESS_RGB_DECORR();
					RGB_PREDLEFT_DECORR_BUF();
				}
			}
			curbuf[width2*3-1] = curbuf[width2*3-2] = curbuf[width2*3-3] = 0;
			for (row = 1; row < height2; row++) {
				pixel_ptr = (height - (interlaced + 1) * row - 1) * mpi->stride[0];
				HUFF_DECOMPRESS_RGB_DECORR();
				RGB_PREDGRAD_DECORR_1ST();
				for (col = 1*3; col < width*3; col += 3) {
					HUFF_DECOMPRESS_RGB_DECORR();
					RGB_PREDGRAD_DECORR();
				}
				if (interlaced) {
					pixel_ptr = (height - 2 * row - 2) * mpi->stride[0];
					for (col = width*3; col < width*6; col += 3) {
						HUFF_DECOMPRESS_RGB_DECORR();
						RGB_PREDGRAD_DECORR();
					}
				}
				SWAPBUF();
			}
			if (oddlines) {
				pixel_ptr = mpi->stride[0];
				HUFF_DECOMPRESS_RGB_DECORR();
				RGB_PREDGRAD_DECORR_1ST();
				for (col = 1*3; col < width*3; col += 3) {
					HUFF_DECOMPRESS_RGB_DECORR();
					RGB_PREDGRAD_DECORR();
				}
			}
		} else {
			/*
			 * RGB predict left (no decorrelation) and predict old
			 */
			/* Store 1st pixel */
			RGB_STORE1ST();
			// Decompress 1st row
			for (col = 1; col < width; col++) {
				HUFF_DECOMPRESS_RGB();
				RGB_PREDLEFT();
			}
			for (row = 1; row < height; row++) {
				pixel_ptr = (height - row - 1) * mpi->stride[0];
				for (col = 0; col < width; col++) {
					HUFF_DECOMPRESS_RGB();
					RGB_PREDLEFT();
				}
			}
		}
	}
    
	return mpi;
}



unsigned char* InitializeDecodeTable(unsigned char* hufftable,
								unsigned char* shift, DecodeTable* decode_table)
{
	unsigned int add_shifted[256];
	char code_lengths[256];
	char code_firstbits[256];
	char table_lengths[32];
	int all_zero_code=-1;
	int i, j, k;
	int firstbit, length, val;
	unsigned char* p;
	unsigned char * table;

	/* Initialize shift[] and add_shifted[] */
	hufftable = InitializeShiftAddTables(hufftable, shift, add_shifted);

	memset(table_lengths, -1, 32);

	/* Fill code_firstbits[], code_legths[] and table_lengths[] */
	for (i = 0; i < 256; ++i) {
		if (add_shifted[i]) {
			for (firstbit = 31; firstbit >= 0; firstbit--) {
				if (add_shifted[i] & (1 << firstbit)) {
					code_firstbits[i] = firstbit;
					length = shift[i] - (32 - firstbit);
					code_lengths[i] = length;
					table_lengths[firstbit] = max(table_lengths[firstbit], length);
					break;
				}
			}
		} else {
			all_zero_code = i;
		}
	}

	p = decode_table->table_data;
	*p++ = 31;
	*p++ = all_zero_code;
	for (j = 0; j < 32; ++j) {
		if (table_lengths[j] == -1) {
			decode_table->table_pointers[j] = decode_table->table_data;
		} else {
			decode_table->table_pointers[j] = p;
			*p++ = j - table_lengths[j];
			p += 1 << table_lengths[j];
		}
	}

	for (k=0; k<256; ++k) {
		if (add_shifted[k]) {
			firstbit = code_firstbits[k];
			val = add_shifted[k] - (1 << firstbit);
			table = decode_table->table_pointers[firstbit];
			memset(&table[1 + (val >> table[0])], k,
						 1 << (table_lengths[firstbit] - code_lengths[k]));
		}
	}

	return hufftable;
}



unsigned char* InitializeShiftAddTables(unsigned char* hufftable,
								unsigned char* shift, unsigned* add_shifted)
{
	int i, j;
	unsigned int bits; // must be 32bit unsigned
	int min_already_processed;
	int max_not_processed;
	int bit;

	// special-case the old tables, since they don't fit the new rules
	if (hufftable == HUFFTABLE_CLASSIC_YUV || hufftable == HUFFTABLE_CLASSIC_RGB) {
		DecompressHuffmanTable(classic_shift_luma, shift);
		for (i = 0; i < 256; ++i)
			add_shifted[i] = classic_add_luma[i] << (32 - shift[i]);
		return (hufftable == HUFFTABLE_CLASSIC_YUV) ? HUFFTABLE_CLASSIC_YUV_CHROMA : hufftable;
	} else if (hufftable == HUFFTABLE_CLASSIC_YUV_CHROMA) {
		DecompressHuffmanTable(classic_shift_chroma, shift);
		for (i = 0; i < 256; ++i)
			add_shifted[i] = classic_add_chroma[i] << (32 - shift[i]);
		return hufftable;
	}

	hufftable = DecompressHuffmanTable(hufftable, shift);

	// derive the actual bit patterns from the code lengths
	min_already_processed = 32;
	bits = 0;
	do {
		max_not_processed = 0;
		for (i = 0; i < 256; ++i) {
			if (shift[i] < min_already_processed && shift[i] > max_not_processed)
				max_not_processed = shift[i];
		}
		bit = 1 << (32 - max_not_processed);
//		assert (!(bits & (bit - 1)));
		for (j = 0; j < 256; ++j) {
			if (shift[j] == max_not_processed) {
				add_shifted[j] = bits;
				bits += bit;
			}
		}
		min_already_processed = max_not_processed;
	} while (bits & 0xFFFFFFFF);

	return hufftable;
}



unsigned char* DecompressHuffmanTable(unsigned char* hufftable,
																			unsigned char* dst)
{
	int val;
	int repeat;
	int i = 0;
	
	do {
		val = *hufftable & 31;
		repeat = *hufftable++ >> 5;
		if (!repeat)
			repeat = *hufftable++;
		while (repeat--)
			dst[i++] = val;
	} while (i < 256);

	return hufftable;
}


unsigned char huff_decompress(unsigned int* in, unsigned int *pos, DecodeTable *decode_table,
															unsigned char *decode_shift)
{
	unsigned int word = *pos >> 5;
	unsigned int bit = *pos & 31;
	unsigned int val = in[word];
	unsigned char outbyte;
	unsigned char *tableptr;
	int i;
	
	if (bit)
		val = (val << bit) | (in[word + 1] >> (32 - bit));
  // figure out the appropriate lookup table based on the number of leading zeros
	i = 31;
	val |= 1;
	while ((val & (1 << i--)) == 0);
	val &= ~(1 << (i+1));
	tableptr = decode_table->table_pointers[i+1]; 
	val >>= *tableptr;

	outbyte = tableptr[val+1];
	*pos += decode_shift[outbyte];

	return outbyte;
}