From 154bf5a17a63b01472abbde0483019db0e903daf Mon Sep 17 00:00:00 2001 From: melanson Date: Thu, 21 Mar 2002 01:21:49 +0000 Subject: added HuffYUV support, courtesy of Roberto Togni git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@5236 b3059339-0415-0410-9bf9-f77b7e298cf2 --- libmpcodecs/Makefile | 2 +- libmpcodecs/vd.c | 2 + libmpcodecs/vd_huffyuv.c | 857 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 860 insertions(+), 1 deletion(-) create mode 100644 libmpcodecs/vd_huffyuv.c (limited to 'libmpcodecs') diff --git a/libmpcodecs/Makefile b/libmpcodecs/Makefile index 4d040d4007..1bf686a96d 100644 --- a/libmpcodecs/Makefile +++ b/libmpcodecs/Makefile @@ -3,7 +3,7 @@ include ../config.mak LIBNAME = libmpcodecs.a -SRCS=dec_video.c vd.c vd_null.c vd_cinepak.c vd_qtrpza.c vd_ffmpeg.c vd_dshow.c vd_vfw.c vd_odivx.c vd_divx4.c vd_raw.c vd_xanim.c vd_msvidc.c vd_fli.c vd_qtrle.c vd_qtsmc.c vd_roqvideo.c vd_cyuv.c vd_nuv.c vd_libmpeg2.c vd_msrle.c +SRCS=dec_video.c vd.c vd_null.c vd_cinepak.c vd_qtrpza.c vd_ffmpeg.c vd_dshow.c vd_vfw.c vd_odivx.c vd_divx4.c vd_raw.c vd_xanim.c vd_msvidc.c vd_fli.c vd_qtrle.c vd_qtsmc.c vd_roqvideo.c vd_cyuv.c vd_nuv.c vd_libmpeg2.c vd_msrle.c vd_huffyuv.c ifeq ($(PNG),yes) SRCS += vd_mpng.c diff --git a/libmpcodecs/vd.c b/libmpcodecs/vd.c index 65e94999e2..1e69d083b3 100644 --- a/libmpcodecs/vd.c +++ b/libmpcodecs/vd.c @@ -44,6 +44,7 @@ extern vd_functions_t mpcodecs_vd_nuv; extern vd_functions_t mpcodecs_vd_mpng; extern vd_functions_t mpcodecs_vd_ijpg; extern vd_functions_t mpcodecs_vd_libmpeg2; +extern vd_functions_t mpcodecs_vd_huffyuv; vd_functions_t* mpcodecs_vd_drivers[] = { &mpcodecs_vd_null, @@ -84,6 +85,7 @@ vd_functions_t* mpcodecs_vd_drivers[] = { &mpcodecs_vd_ijpg, #endif &mpcodecs_vd_libmpeg2, + &mpcodecs_vd_huffyuv, NULL }; diff --git a/libmpcodecs/vd_huffyuv.c b/libmpcodecs/vd_huffyuv.c new file mode 100644 index 0000000000..e676283c1f --- /dev/null +++ b/libmpcodecs/vd_huffyuv.c @@ -0,0 +1,857 @@ +/* + * + * 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 +#include + +#include "config.h" +#include "mp_msg.h" + +#include "vd_internal.h" + + +static vd_info_t info = { + "HuffYUV Video decoder", + "huffyuv", + VFM_HUFFYUV, + "Roberto Togni", + "Roberto Togni", + "native codec, original win32 by Ben Rudiak-Gould http://www.math.berkeley.edu/~benrg/huffyuv.html" +}; + +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; + // 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,...){ + 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; + + mp_msg(MSGT_DECVIDEO, MSGL_V, "[HuffYUV] Allocating above line buffer\n"); + if ((hc->abovebuf1 = malloc(sizeof(char) * 4 * bih->biWidth)) == 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)) == NULL) { + mp_msg(MSGT_DECVIDEO, MSGL_ERR, "Can't allocate memory for HuffYUV above buffer 2\n"); + return 0; + } + + 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"); + } + + /* 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 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() \ +{ \ + outptr[pixel_ptr++] = left_b += b; \ + outptr[pixel_ptr++] = left_g += g; \ + outptr[pixel_ptr++] = left_r += r; \ + pixel_ptr += bgr32; \ +} + + + + +/* + * + * 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 bgr32; + + // skipped frame + if(len <= 0) + return NULL; + + /* Do not accept stride for rgb, it gives me wrong output :-( */ + if (hc->bitmaptype == BMPTYPE_YUV) + mpi=mpcodecs_get_image(sh, MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, sh->disp_w, sh->disp_h); + else + mpi=mpcodecs_get_image(sh, MP_IMGTYPE_TEMP, 0, 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 + 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); + } + curbuf[width*4-1] = curbuf[width*4-2] = curbuf[width*4-3] = 0; + for (row = 1; row < height; row++) { + pixel_ptr = row * mpi->stride[0]; + HUFF_DECOMPRESS_YUYV(); + curbuf[0] = outptr[pixel_ptr++] = left_y += y1 + abovebuf[0] - curbuf[width*4-2]; + curbuf[1] = outptr[pixel_ptr++] = left_u += u + abovebuf[1] - curbuf[width*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[width*4+3-4]; + for (col = 1*4; col < width*4; col += 4) { + HUFF_DECOMPRESS_YUYV(); + 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]; + } + swap = abovebuf; + abovebuf = curbuf; + curbuf = swap; + } + } 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); + } + // Decompress 1st two pixels of 2nd row + pixel_ptr = mpi->stride[0]; + 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(); + } + swap = abovebuf; + abovebuf = curbuf; + curbuf = swap; + for (row = 2; row < height; row++) { + pixel_ptr = row * mpi->stride[0]; + HUFF_DECOMPRESS_YUYV(); + MEDIAN (left_y, abovebuf[0], curbuf[width*4-2]); + curbuf[0] = outptr[pixel_ptr++] = left_y = med + y1; + MEDIAN (left_u, abovebuf[1], curbuf[width*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[width*4+3-4]); + curbuf[3] = outptr[pixel_ptr++] = left_v = med + v; + for (col = 1*4; col < width*4; col += 4) { + HUFF_DECOMPRESS_YUYV(); + YUV_PREDMED(); + } + swap = abovebuf; + abovebuf = curbuf; + curbuf = swap; + } + } 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(); + 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; + } + curbuf[width*3-1] = curbuf[width*3-2] = curbuf[width*3-3] = 0; + for (row = 1; row < height; row++) { + pixel_ptr = (height - row - 1) * mpi->stride[0]; + HUFF_DECOMPRESS_RGB_DECORR(); + curbuf[0] = outptr[pixel_ptr++] = left_b += b + g + abovebuf[0] - curbuf[width*3-3]; + curbuf[1] = outptr[pixel_ptr++] = left_g += g + abovebuf[1] - curbuf[width*3+1-3]; + curbuf[2] = outptr[pixel_ptr++] = left_r += r + g + abovebuf[2] - curbuf[width*3+2-3]; + pixel_ptr += bgr32; + for (col = 1*3; col < width*3; col += 3) { + HUFF_DECOMPRESS_RGB_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; + } + swap = abovebuf; + abovebuf = curbuf; + curbuf = swap; + } + } 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; +} -- cgit v1.2.3