From 54c77d2cb0f734615febdb3cb33548bf4cd6e953 Mon Sep 17 00:00:00 2001 From: Pixel Date: Sun, 23 Jun 2002 11:19:06 +0000 Subject: Pfiou, huge work... --- FAQ-cd.txt | 51 ++- Makefile | 10 +- generic.h | 27 +- psxdev/Makefile | 9 +- psxdev/bs.c | 697 ++++++++++++++++--------------- psxdev/bs.h | 32 +- psxdev/idctfst.c | 56 +-- psxdev/jfdctint.c | 24 +- psxdev/table.h | 204 ++++----- psxdev/vlc.c | 1208 +++++++++++++++++++++++++++-------------------------- psxdev/xadecode.c | 301 +++++++++++++ psxdev/xadecode.h | 82 ++++ str-util.cpp | 96 ++++- 13 files changed, 1668 insertions(+), 1129 deletions(-) create mode 100644 psxdev/xadecode.c create mode 100644 psxdev/xadecode.h diff --git a/FAQ-cd.txt b/FAQ-cd.txt index 8259372..e3b630e 100644 --- a/FAQ-cd.txt +++ b/FAQ-cd.txt @@ -194,18 +194,53 @@ int is_valid_BCD(uchar x) {return (((x & 15) < 10) && ((x >> 4) < 10));} 5: Form 2 6: Real Time (RT) 7: End of File (EOF) - but it seems it's not very accurate, as you will se below. Of course, the PSX has the CDs in MODE 2... So the common files are stored in MODE 2 FORM 1, the STR/XA files are stored in "MODE 2" but actually they are in MODE 2 FORM 1/2. The MOVCONV tool will in fact produce - files that does contain the subheaders. And those subheaders seems to - contain a CN equals to 1, and the flags RT and Data are activated for the - video frames, and FN, CN, and CI equal to 1, and the flags are placed - as it: RT, Form 2, Audio for Audio streams. So the Video frames are in - plain Form 1, and the Audio frames are in plain Form 2. But it _seems_ the - Video frames are not checked against ECC/EDC, but filled with zeros - instead. + files that does contain the subheaders. + + Those subheaders are very likely to vary, and seems to be very important for + stream processing. Please note that "str" video sectors are considered as + data sectors, and not as video sectors. + + The CN byte indicates the channel number of the current sector. The XA + format may contain interlaced channels. So for example, if you have a + file that does contain 8 channels, you will have first the first sector + of the channel 0, then the first sector of the channel 1, etc... + + This is also a bit more difficult when you know that video is also + interlaced and considered as a channel itself. The common interlacement + is 7 video sectors for 1 audio sector, but this may vary. And all the + channels may be completely independants. For example, you may have a + sound-free video that does contain an audio channel, this audio channel + may be used for another part in the game. + + This is to optimize the reading process. Since the cd reader is a 2x cd + reader, it *HAS* to read data in full 300KBps. So, if you have a sound + free video, the reading process will be faster than the decoding process, + and everything will crash. This is about the same for the audio sectors. + The 'leap' sector function of MOVCONV does add blank sectors in order to + pad the channels that may have stopped before the others. + + One "speed" of the CD reader corresponds to four time the playback speed + of a stereo audio channel at 37800Hz. So at full speed you can have eight + stereo audio channels at 37800Hz. Or you can have 32 mono audio channels + at 18900Hz. + + Common video str files needs 7/8 of the full speed of the CD reader. + "Common" means 320x224 videos at 15fps. So you can have a full movie + in 320x224x15fps with a stereo sound track at 37800hz. So, now, you + may understand why the common interlacement may vary. + + The CI byte does contains some flags about the current sector, but I'm + yet unable to give a full description of them. I've only got this: for + audio frames, the bit 0 is set when you have stereo sound, and the bit 2 + is set when you have "half frequency", ie 18900Hz instead of 37800Hz. + + The Video frames are in plain Form 1, and the Audio frames are in plain + Form 2. But it _seems_ the Video frames are not checked against ECC/EDC, + and filled with zeros instead. The last but not the least: the MODE 2 FORM 1 and MODE 2 FORM 2 are also called XA-Mode1 and XA-Mode2 or simplier: XA-1 and XA-2. diff --git a/Makefile b/Makefile index 6f57c0e..a8c788e 100755 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ TARGET = lzss dlzss cd-tool str-tool all: subdirs ${TARGET} subdirs: - for d in ${SUBDIRS} ; do (cd $$d ; make all) ; done + for d in ${SUBDIRS} ; do make -C $$d ; done lzss: lzss.o lzss.h generic.o generic.h fileutils.h fileutils.o lzss-main.o ${CXX} ${LDFLAGS} -DLZSS_MAIN lzss.o generic.o fileutils.o lzss-main.o -o lzss @@ -18,16 +18,16 @@ dlzss: lzss ln -fs lzss dlzss yazedc: yazedc.o crctables crctable.out yazedc-main.o - ${CXX} ${CPPFLAGS} ${LDFLAGS} yazedc.o yazedc-main.o -DMAIN -o yazedc + ${CXX} ${LDFLAGS} yazedc.o yazedc-main.o -DMAIN -o yazedc cd-tool: cd-tool.o cdutils.o cdutils.h fileutils.o fileutils.h generic.o generic.h yazedc.o yazedc.h - ${CXX} ${oFLAGS} ${LDFLAGAS} cd-tool.o cdutils.o fileutils.o yazedc.o generic.o -o cd-tool + ${CXX} ${LDFLAGAS} cd-tool.o cdutils.o fileutils.o yazedc.o generic.o -o cd-tool dte-tool: dteutils.o generic.h generic.o fileutils.o fileutils.h dtemain.o - ${CXX} ${oFLAGS} ${LDFLAGS} dteutils.o generic.o fileutils.o dtemain.o -o dte-tool + ${CXX} ${LDFLAGS} dteutils.o generic.o fileutils.o dtemain.o -o dte-tool str-tool: str-util.o generic.h generic.o fileutils.o fileutils.h cdutils.o cdutils.h yazedc.o yazedc.h - ${CXX} ${oFLAGS} ${LDFLAGS} str-util.o generic.o fileutils.o cdutils.o yazedc.o psxdev/bs.o psxdev/idctfst.o psxdev/jfdctint.o psxdev/vlc.o -o str-tool + ${CXX} ${LDFLAGS} str-util.o generic.o fileutils.o cdutils.o yazedc.o psxdev/bs.o psxdev/idctfst.o psxdev/jfdctint.o psxdev/vlc.o -o str-tool -lSDL clean: rm -f *.o ${TARGET} compil.c diff --git a/generic.h b/generic.h index 86dafaa..ee9bb0e 100644 --- a/generic.h +++ b/generic.h @@ -32,17 +32,42 @@ #define MIN(a,b) ((a)<(b)?(a):(b)) #define MAX(a,b) ((a)<(b)?(b):(a) - +/* +#ifndef Uint32 typedef unsigned long int Uint32; +#endif +*/ +#ifndef int32 typedef signed long int int32; +#endif + +#ifndef Uint16 typedef unsigned short int Uint16; +#endif + +#ifndef int16 typedef signed short int int16; +#endif + +#ifndef Uint8 typedef unsigned char Uint8; +#endif + +#ifndef int8 typedef signed char int8; +#endif +#ifndef Byte typedef Uint8 Byte; +#endif + +#ifndef Word typedef Uint16 Word; +#endif + +#ifndef DWord typedef Uint32 DWord; +#endif extern char verbosity; void printm(int level, char * fmt, ...); diff --git a/psxdev/Makefile b/psxdev/Makefile index 3db2a0f..5cc33ca 100644 --- a/psxdev/Makefile +++ b/psxdev/Makefile @@ -1,10 +1,15 @@ -TARGETS=bs.o idctfst.o jfdctint.o vlc.o +TARGETS=xadecode.o bs.o idctfst.o jfdctint.o vlc.o CC=gcc -CPPFLAGS=-march=i386 -O3 +CPPFLAGS=-Wall -g -O3 -mcpu=i686 -pedantic +# -Werror +# -pedantic-errors all: $(TARGETS) +bstoppm: xadecode.o bs.o idctfst.o jfdtint.o vlc.o bstoppm.o + ${CC} ${LDFLAGS} xadecode.o bs.o idcfst.o jfdtint.o vlc.o bstoppm.o -o bstoppm + clean: rm -f *.o diff --git a/psxdev/bs.c b/psxdev/bs.c index 5d7e185..5823430 100644 --- a/psxdev/bs.c +++ b/psxdev/bs.c @@ -1,348 +1,349 @@ -/* - (c)2000 by BERO bero@geocities.co.jp - - under GPL - - some changes by dbalster@psxdev.de - - - all globals now in a context (to use it as shlib) - - removed debugging printfs -*/ - -typedef struct { -/* bit i/o */ - unsigned int bitbuf; - int bitcount,bs_size,totalbit; - unsigned short *bsbuf; -/* huffman */ - int last_dc[3]; - int _type; - int rlsize; - unsigned char *iqtab; -} bs_context_t; - -#include "bs.h" -#include "common.h" - -static const char *copyright = N_("Copyright (C) 2000 by Daniel Balster "); - -enum {B,G,R}; -typedef int BLOCK; - -#define DCTSIZE2 64 -#define RGB2Y(r,g,b) ( 0.299*(r) + 0.587*(g) + 0.114*(b) ) -#define RGB2Cb(r,g,b) ( -0.16874*(r) - 0.33126*(g) +0.5*(b) ) -#define RGB2Cr(r,g,b) ( 0.5*(r) - 0.41869*(g) - 0.08131*(b) ) - -/* -16x16 RGB -> 8x8 Cb,Cr,Y0,Y1,Y2,Y3 - -[Y0][Y1] [Cb] [Cr] -[Y2][Y3] -*/ -#define Cb 0 -#define Cr DCTSIZE2 - -static void rgb2yuv (unsigned char image[][3], BLOCK *blk) -{ - int x,y,i; - int tmpblk[16*16][3],(*yuv)[3]; - BLOCK *yblk; - - yuv=tmpblk; - for(i=0;i<16*16;i++) { - yuv[0][0] = RGB2Y (image[0][R],image[0][G],image[0][B])-128; - yuv[0][1] = RGB2Cb(image[0][R],image[0][G],image[0][B]); - yuv[0][2] = RGB2Cr(image[0][R],image[0][G],image[0][B]); - yuv++; image++; - } - - yuv = tmpblk; - yblk = blk+DCTSIZE2*2; - for(y=0;y<16;y+=2,blk+=4,yblk+=8,yuv+=8+16) { - if (y==8) yblk+=DCTSIZE2; - for(x=0;x<4;x++,blk++,yblk+=2,yuv+=2) { - blk[Cb] = (yuv[0][1]+yuv[1][1]+yuv[16][1]+yuv[17][1])/4; - blk[Cr] = (yuv[0][2]+yuv[1][2]+yuv[16][2]+yuv[17][2])/4; - yblk[0] = yuv[ 0][0]; - yblk[1] = yuv[ 1][0]; - yblk[8] = yuv[16][0]; - yblk[9] = yuv[17][0]; - - blk[4+Cb] = (yuv[8+0][1]+yuv[8+1][1]+yuv[8+16][1]+yuv[8+17][1])/4; - blk[4+Cr] = (yuv[8+0][2]+yuv[8+1][2]+yuv[8+16][2]+yuv[8+17][2])/4; - yblk[DCTSIZE2+0] = yuv[8+ 0][0]; - yblk[DCTSIZE2+1] = yuv[8+ 1][0]; - yblk[DCTSIZE2+8] = yuv[8+16][0]; - yblk[DCTSIZE2+9] = yuv[8+17][0]; - } - } -} - -#undef Cb -#undef Cr - -/* bit i/o */ -#define BITBUFSIZE 16 -#define WriteWord(x) ctxt->bsbuf[ctxt->bs_size++]=(x) - -static void putbits_init (bs_context_t *ctxt) -{ - ctxt->bitbuf = 0; - ctxt->bitcount = BITBUFSIZE; - ctxt->bs_size = 0; - ctxt->totalbit = 0; -} - -static void putbits_flush (bs_context_t *ctxt) -{ - WriteWord(ctxt->bitbuf); -} - -static void putbits (bs_context_t *ctxt, unsigned int x, unsigned int n) -{ - ctxt->totalbit+=n; - - if (nbitcount) { - ctxt->bitcount-=n; - ctxt->bitbuf |= x << ctxt->bitcount; - } else { - n-=ctxt->bitcount; - WriteWord(ctxt->bitbuf | (x>>n) ); - if (nbitcount = BITBUFSIZE-n; - } else { - WriteWord( x>>(n-BITBUFSIZE) ); - ctxt->bitcount = BITBUFSIZE*2-n; - } - ctxt->bitbuf = x << ctxt->bitcount; - } -} - -typedef struct { - unsigned char code,nbits; -} huff_t; - -const static huff_t dc_y_table[] = { - {4,3},{0,2},{1,2},{5,3},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8} -}; - -const static huff_t dc_c_table[] = { - {0,2},{1,2},{2,2},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9} -}; - -#include "table.h" - -static void encode_init (bs_context_t *ctxt, void *outbuf, int type, int q_scale) -{ - ctxt->_type = type; - ctxt->last_dc[0] = 0; - ctxt->last_dc[1] = 0; - ctxt->last_dc[2] = 0; - ctxt->rlsize = 0; - putbits_init(ctxt); - - ctxt->bsbuf = outbuf; - ctxt->bsbuf[1] = 0x3800; - ctxt->bsbuf[2] = q_scale; - ctxt->bsbuf[3] = type; - ctxt->bs_size+=4; -} - -static void encode_finish (bs_context_t *ctxt) -{ - putbits_flush(ctxt); - ctxt->bsbuf[0] = (((ctxt->rlsize+1)/2)+31)&~31; -} - -static void encode_dc (bs_context_t *ctxt, int n, int level) -{ - if (ctxt->_type==2) { - putbits(ctxt,level&0x3ff,10); - } else { - const huff_t *table; - int prev,cnt; - - level = level/4; - if (n<2) { - table = dc_c_table; - prev = ctxt->last_dc[n]; - ctxt->last_dc[n] = level; - } else { - table = dc_y_table; - prev = ctxt->last_dc[2]; - ctxt->last_dc[2] = level; - } - level -= prev; - if (level==0) cnt=0; - else { - int alevel = level; - if (alevel<0) alevel=-alevel; - for(cnt=8;(alevel>>cnt)==0;cnt--); - cnt++; - if (level<0) level--; - } - putbits(ctxt,table[cnt].code,table[cnt].nbits); - if (cnt) putbits(ctxt,level&((1<rlsize++; -} - -static void encode_ac (bs_context_t *ctxt, int run, int level) -{ - int abslevel,sign; - if (level>0) { - abslevel = level; - sign = 0; - } else { - abslevel = -level; - sign = 1; - } - if (run<=31 && abslevel<=maxlevel[run]) { - putbits(ctxt,huff_table[run][abslevel-1].code+sign,huff_table[run][abslevel-1].nbits); - } else { - /* ESCAPE */ - putbits(ctxt,1,6); - putbits(ctxt,(run<<10)+(level&0x3ff),16); - } - ctxt->rlsize++; -} - -static void encode_eob (bs_context_t *ctxt) -{ - putbits(ctxt, 2,2); - ctxt->rlsize++; -} - -extern DCT(BLOCK *blk); - -unsigned char zscan[DCTSIZE2] = { - 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 -}; - -static unsigned char xxx_iqtab[DCTSIZE2] = { - 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 -}; - -const unsigned char *bs_iqtab (void) { return xxx_iqtab; } - -static void blk2huff (bs_context_t *ctxt,BLOCK *blk,int q_scale) -{ - int i,k,run,level; - for(i=0;i<6;i++) { - DCT(blk); - for(k=0;k>=3; - level = blk[0]/ctxt->iqtab[0]; - encode_dc(ctxt,i,level); - run = 0; - for(k=1;k<64;k++) { - level = blk[zscan[k]]*8/(ctxt->iqtab[zscan[k]]*q_scale); - if (level==0) { - run++; - } else { - encode_ac(ctxt,run,level); - run=0; - } - } - encode_eob(ctxt); - blk+=DCTSIZE2; - } -} - -u_char bs_roundtbl[256*3]; - -void bs_init (void) -{ - int i; - for(i=0;i<256;i++) { - bs_roundtbl [i]=0; - bs_roundtbl [i+256]=i; - bs_roundtbl [i+512]=255; - } -} - -int bs_encode (bs_header_t *outbuf,bs_input_image_t *img,int type,int q_scale, - unsigned char *myiqtab) -{ - unsigned char image[16][16][3]; - BLOCK blk[6][DCTSIZE2]; - bs_context_t *ctxt = malloc(sizeof(bs_context_t)); - - int x,y,xw,yw,rl; - - ctxt->iqtab = myiqtab ? myiqtab : bs_iqtab(); - - encode_init (ctxt,outbuf,type,q_scale); - - for(x=0;xwidth;x+=16) { - xw = img->width-x; if (xw>16) xw = 16; - for(y=0;yheight;y+=16) { - char *p0 = img->top + x*(img->bit)/8 + y*img->nextline; - int i,j=0; - yw = img->height-y; if (yw>16) yw = 16; - - /* get 16x16 image */ - - for(i=0;inextline; - switch(img->bit) { - case 16: - for(j=0;j>10)&31)*8; - image[i][j][G] = ((c>>5)&31)*8; - image[i][j][R] = ((c&31))*8; - p+=2; - } - break; - case 24: - for(j=0;jbs_size * 2); - free (ctxt); - - return rl; -} +/* + (c)2000 by BERO bero@geocities.co.jp + + under GPL + + some changes by dbalster@psxdev.de + + - all globals now in a context (to use it as shlib) + - removed debugging printfs +*/ + +typedef struct { +/* bit i/o */ + unsigned int bitbuf; + int bitcount,bs_size,totalbit; + unsigned short *bsbuf; +/* huffman */ + int last_dc[3]; + int _type; + int rlsize; + const unsigned char *iqtab; +} bs_context_t; + +#include +#include "bs.h" +#include "common.h" + +/* static const char *copyright = N_("Copyright (C) 2000 by Daniel Balster "); */ + +enum {B,G,R}; +typedef int BLOCK; + +#define DCTSIZE2 64 +#define RGB2Y(r,g,b) ( 0.299*(r) + 0.587*(g) + 0.114*(b) ) +#define RGB2Cb(r,g,b) ( -0.16874*(r) - 0.33126*(g) +0.5*(b) ) +#define RGB2Cr(r,g,b) ( 0.5*(r) - 0.41869*(g) - 0.08131*(b) ) + +/* +16x16 RGB -> 8x8 Cb,Cr,Y0,Y1,Y2,Y3 + +[Y0][Y1] [Cb] [Cr] +[Y2][Y3] +*/ +#define Cb 0 +#define Cr DCTSIZE2 + +static void rgb2yuv (unsigned char image[][3], BLOCK *blk) +{ + int x,y,i; + int tmpblk[16*16][3],(*yuv)[3]; + BLOCK *yblk; + + yuv=tmpblk; + for(i=0;i<16*16;i++) { + yuv[0][0] = RGB2Y (image[0][R],image[0][G],image[0][B])-128; + yuv[0][1] = RGB2Cb(image[0][R],image[0][G],image[0][B]); + yuv[0][2] = RGB2Cr(image[0][R],image[0][G],image[0][B]); + yuv++; image++; + } + + yuv = tmpblk; + yblk = blk+DCTSIZE2*2; + for(y=0;y<16;y+=2,blk+=4,yblk+=8,yuv+=8+16) { + if (y==8) yblk+=DCTSIZE2; + for(x=0;x<4;x++,blk++,yblk+=2,yuv+=2) { + blk[Cb] = (yuv[0][1]+yuv[1][1]+yuv[16][1]+yuv[17][1])/4; + blk[Cr] = (yuv[0][2]+yuv[1][2]+yuv[16][2]+yuv[17][2])/4; + yblk[0] = yuv[ 0][0]; + yblk[1] = yuv[ 1][0]; + yblk[8] = yuv[16][0]; + yblk[9] = yuv[17][0]; + + blk[4+Cb] = (yuv[8+0][1]+yuv[8+1][1]+yuv[8+16][1]+yuv[8+17][1])/4; + blk[4+Cr] = (yuv[8+0][2]+yuv[8+1][2]+yuv[8+16][2]+yuv[8+17][2])/4; + yblk[DCTSIZE2+0] = yuv[8+ 0][0]; + yblk[DCTSIZE2+1] = yuv[8+ 1][0]; + yblk[DCTSIZE2+8] = yuv[8+16][0]; + yblk[DCTSIZE2+9] = yuv[8+17][0]; + } + } +} + +#undef Cb +#undef Cr + +/* bit i/o */ +#define BITBUFSIZE 16 +#define WriteWord(x) ctxt->bsbuf[ctxt->bs_size++]=(x) + +static void putbits_init (bs_context_t *ctxt) +{ + ctxt->bitbuf = 0; + ctxt->bitcount = BITBUFSIZE; + ctxt->bs_size = 0; + ctxt->totalbit = 0; +} + +static void putbits_flush (bs_context_t *ctxt) +{ + WriteWord(ctxt->bitbuf); +} + +static void putbits (bs_context_t *ctxt, unsigned int x, unsigned int n) +{ + ctxt->totalbit+=n; + + if (nbitcount) { + ctxt->bitcount-=n; + ctxt->bitbuf |= x << ctxt->bitcount; + } else { + n-=ctxt->bitcount; + WriteWord(ctxt->bitbuf | (x>>n) ); + if (nbitcount = BITBUFSIZE-n; + } else { + WriteWord( x>>(n-BITBUFSIZE) ); + ctxt->bitcount = BITBUFSIZE*2-n; + } + ctxt->bitbuf = x << ctxt->bitcount; + } +} + +typedef struct { + unsigned int code,nbits; +} huff_t; + +const static huff_t dc_y_table[] = { + {4,3},{0,2},{1,2},{5,3},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8} +}; + +const static huff_t dc_c_table[] = { + {0,2},{1,2},{2,2},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9} +}; + +#include "table.h" + +static void encode_init (bs_context_t *ctxt, void *outbuf, int type, int q_scale) +{ + ctxt->_type = type; + ctxt->last_dc[0] = 0; + ctxt->last_dc[1] = 0; + ctxt->last_dc[2] = 0; + ctxt->rlsize = 0; + putbits_init(ctxt); + + ctxt->bsbuf = outbuf; + ctxt->bsbuf[1] = 0x3800; + ctxt->bsbuf[2] = q_scale; + ctxt->bsbuf[3] = type; + ctxt->bs_size+=4; +} + +static void encode_finish (bs_context_t *ctxt) +{ + putbits_flush(ctxt); + ctxt->bsbuf[0] = (((ctxt->rlsize+1)/2)+31)&~31; +} + +static void encode_dc (bs_context_t *ctxt, int n, int level) +{ + if (ctxt->_type==2) { + putbits(ctxt,level&0x3ff,10); + } else { + const huff_t *table; + int prev,cnt; + + level = level/4; + if (n<2) { + table = dc_c_table; + prev = ctxt->last_dc[n]; + ctxt->last_dc[n] = level; + } else { + table = dc_y_table; + prev = ctxt->last_dc[2]; + ctxt->last_dc[2] = level; + } + level -= prev; + if (level==0) cnt=0; + else { + int alevel = level; + if (alevel<0) alevel=-alevel; + for(cnt=8;(alevel>>cnt)==0;cnt--); + cnt++; + if (level<0) level--; + } + putbits(ctxt,table[cnt].code,table[cnt].nbits); + if (cnt) putbits(ctxt,level&((1<rlsize++; +} + +static void encode_ac (bs_context_t *ctxt, int run, int level) +{ + int abslevel,sign; + if (level>0) { + abslevel = level; + sign = 0; + } else { + abslevel = -level; + sign = 1; + } + if (run<=31 && abslevel<=maxlevel[run]) { + putbits(ctxt,huff_table[run][abslevel-1].code+sign,huff_table[run][abslevel-1].nbits); + } else { + /* ESCAPE */ + putbits(ctxt,1,6); + putbits(ctxt,(run<<10)+(level&0x3ff),16); + } + ctxt->rlsize++; +} + +static void encode_eob (bs_context_t *ctxt) +{ + putbits(ctxt, 2,2); + ctxt->rlsize++; +} + +extern void DCT(BLOCK *blk); + +unsigned char zscan[DCTSIZE2] = { + 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 +}; + +static unsigned char xxx_iqtab[DCTSIZE2] = { + 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 +}; + +const unsigned char *bs_iqtab (void) { return xxx_iqtab; } + +static void blk2huff (bs_context_t *ctxt,BLOCK *blk,int q_scale) +{ + int i,k,run,level; + for(i=0;i<6;i++) { + DCT(blk); + for(k=0;k>=3; + level = blk[0]/ctxt->iqtab[0]; + encode_dc(ctxt,i,level); + run = 0; + for(k=1;k<64;k++) { + level = blk[zscan[k]]*8/(ctxt->iqtab[zscan[k]]*q_scale); + if (level==0) { + run++; + } else { + encode_ac(ctxt,run,level); + run=0; + } + } + encode_eob(ctxt); + blk+=DCTSIZE2; + } +} + +u_char bs_roundtbl[256*3]; + +void bs_init (void) +{ + int i; + for(i=0;i<256;i++) { + bs_roundtbl [i]=0; + bs_roundtbl [i+256]=i; + bs_roundtbl [i+512]=255; + } +} + +int bs_encode (bs_header_t *outbuf,bs_input_image_t *img,int type,int q_scale, + const unsigned char *myiqtab) +{ + unsigned char image[16][16][3]; + BLOCK blk[6][DCTSIZE2]; + bs_context_t *ctxt = malloc(sizeof(bs_context_t)); + + int x,y,xw,yw,rl; + + ctxt->iqtab = myiqtab ? myiqtab : bs_iqtab(); + + encode_init (ctxt,outbuf,type,q_scale); + + for(x=0;xwidth;x+=16) { + xw = img->width-x; if (xw>16) xw = 16; + for(y=0;yheight;y+=16) { + unsigned char *p0 = img->top + x*(img->bit)/8 + y*img->nextline; + int i,j=0; + yw = img->height-y; if (yw>16) yw = 16; + + /* get 16x16 image */ + + for(i=0;inextline; + switch(img->bit) { + case 16: + for(j=0;j>10)&31)*8; + image[i][j][G] = ((c>>5)&31)*8; + image[i][j][R] = ((c&31))*8; + p+=2; + } + break; + case 24: + for(j=0;jbs_size * 2); + free (ctxt); + + return rl; +} diff --git a/psxdev/bs.h b/psxdev/bs.h index d8d9a6c..47a3762 100644 --- a/psxdev/bs.h +++ b/psxdev/bs.h @@ -1,4 +1,4 @@ -/* $Id: bs.h,v 1.1 2002-06-21 23:45:51 Pixel Exp $ */ +/* $Id: bs.h,v 1.2 2002-06-23 11:19:06 Pixel Exp $ */ /* libbs - library for the bitstream image format @@ -30,7 +30,9 @@ #ifndef __LIB_BS_H #define __LIB_BS_H +#ifndef _GNU_SOURCE #define _GNU_SOURCE +#endif #include #include @@ -60,26 +62,26 @@ extern "C" { void bs_init (void); -int bs_encode ( // returns BS image size in bytes - bs_header_t *outbuf, // output BS image - bs_input_image_t *img, // input image descriptor - int type, // image type (use BS_TYPE) - int q_scale, // Q scaling factor (1=best,>= lower quality) - unsigned char *myiqtab // provide own iqtab (NULL == default) +int bs_encode ( /* returns BS image size in bytes */ + bs_header_t *outbuf, /* output BS image */ + bs_input_image_t *img, /* input image descriptor */ + int type, /* image type (use BS_TYPE) */ + int q_scale, /* Q scaling factor (1=best,>= lower quality) */ + const unsigned char *myiqtab /* provide own iqtab (NULL == default) */ ); void bs_decode_rgb24 ( - unsigned char *outbuf, // output RGB bytes (width*height*3) - bs_header_t *img, // input BS image - int width, int height, // dimension of BS image - unsigned char *myiqtab + unsigned char *outbuf, /* output RGB bytes (width*height*3) */ + bs_header_t *img, /* input BS image */ + int width, int height, /* dimension of BS image */ + const unsigned char *myiqtab ); void bs_decode_rgb15 ( - unsigned short *outbuf, // output RGB bytes (width*height*2) - bs_header_t *img, // input BS image - int width, int height, // dimension of BS image - unsigned char *myiqtab + unsigned short *outbuf, /* output RGB bytes (width*height*2) */ + bs_header_t *img, /* input BS image */ + int width, int height, /* dimension of BS image */ + const unsigned char *myiqtab ); const unsigned char *bs_iqtab (void); diff --git a/psxdev/idctfst.c b/psxdev/idctfst.c index 22faae6..345cdb1 100644 --- a/psxdev/idctfst.c +++ b/psxdev/idctfst.c @@ -59,7 +59,7 @@ * machines, and may also reduce the cost of multiplication (since there * are fewer one-bits in the constants). */ - + #define BITS_IN_JSAMPLE 8 #if BITS_IN_JSAMPLE == 8 @@ -108,7 +108,7 @@ * multiplication will do. For 12-bit data, the multiplier table is * declared INT32, so a 32-bit multiply will be used. */ - + #if BITS_IN_JSAMPLE == 8 #define DEQUANTIZE(coef,quantval) (coef) #else @@ -121,24 +121,24 @@ * We assume that int right shift is unsigned if INT32 right shift is. */ -#define DESCALE(x,n) ((x)>>(n)) +#define DESCALE(x,n) ((x)>>(n)) #define RANGE(n) (n) -#define BLOCK int +#define BLOCK int /* * Perform dequantization and inverse DCT on one block of coefficients. */ -#define DCTSIZE 8 -#define DCTSIZE2 64 - -static void IDCT1(BLOCK *block) -{ +#define DCTSIZE 8 +#define DCTSIZE2 64 + +static void IDCT1(BLOCK *block) +{ int val = RANGE(DESCALE(block[0], PASS1_BITS+3)); - int i; - for(i=0;i>(n)) -#define GLOBAL +#define RIGHT_SHIFT(x,n) ((x)>>(n)) +#define GLOBAL #define jpeg_fdct_islow DCT -#define SHIFT_TEMPS -//#define BITS_IN_JSAMPLE 8 -//#define MULTIPLY16C16(var,const) ((var) * (const)) - - +#define SHIFT_TEMPS +/* #define BITS_IN_JSAMPLE 8 + #define MULTIPLY16C16(var,const) ((var) * (const)) */ + + #ifdef DCT_ISLOW_SUPPORTED @@ -44,7 +44,7 @@ */ #if DCTSIZE != 8 - Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#error Sorry, this code only copes with 8x8 DCTs. #endif diff --git a/psxdev/table.h b/psxdev/table.h index 3e50b18..0b50ad3 100644 --- a/psxdev/table.h +++ b/psxdev/table.h @@ -1,102 +1,102 @@ -const static huff_t table0[]={ - {6,3},{8,5},{10,6},{12,8},{76,9},{66,9},{20,11},{58,13},{48,13},{38,13},{32,13},{52,14},{50,14},{48,14},{46,14},{62,15},{60,15},{58,15},{56,15},{54,15},{52,15},{50,15},{48,15},{46,15},{44,15},{42,15},{40,15},{38,15},{36,15},{34,15},{32,15},{48,16},{46,16},{44,16},{42,16},{40,16},{38,16},{36,16},{34,16},{32,16}, -}; -const static huff_t table1[]={ - {6,4},{12,7},{74,9},{24,11},{54,13},{44,14},{42,14},{62,16},{60,16},{58,16},{56,16},{54,16},{52,16},{50,16},{38,17},{36,17},{34,17},{32,17}, -}; -const static huff_t table2[]={ - {10,5},{8,8},{22,11},{40,13},{40,14}, -}; -const static huff_t table3[]={ - {14,6},{72,9},{56,13},{38,14}, -}; -const static huff_t table4[]={ - {12,6},{30,11},{36,13}, -}; -const static huff_t table5[]={ - {14,7},{18,11},{36,14}, -}; -const static huff_t table6[]={ - {10,7},{60,13},{40,17}, -}; -const static huff_t table7[]={ - {8,7},{42,13}, -}; -const static huff_t table8[]={ - {14,8},{34,13}, -}; -const static huff_t table9[]={ - {10,8},{34,14}, -}; -const static huff_t table10[]={ - {78,9},{32,14}, -}; -const static huff_t table11[]={ - {70,9},{52,17}, -}; -const static huff_t table12[]={ - {68,9},{50,17}, -}; -const static huff_t table13[]={ - {64,9},{48,17}, -}; -const static huff_t table14[]={ - {28,11},{46,17}, -}; -const static huff_t table15[]={ - {26,11},{44,17}, -}; -const static huff_t table16[]={ - {16,11},{42,17}, -}; -const static huff_t table17[]={ - {62,13}, -}; -const static huff_t table18[]={ - {52,13}, -}; -const static huff_t table19[]={ - {50,13}, -}; -const static huff_t table20[]={ - {46,13}, -}; -const static huff_t table21[]={ - {44,13}, -}; -const static huff_t table22[]={ - {62,14}, -}; -const static huff_t table23[]={ - {60,14}, -}; -const static huff_t table24[]={ - {58,14}, -}; -const static huff_t table25[]={ - {56,14}, -}; -const static huff_t table26[]={ - {54,14}, -}; -const static huff_t table27[]={ - {62,17}, -}; -const static huff_t table28[]={ - {60,17}, -}; -const static huff_t table29[]={ - {58,17}, -}; -const static huff_t table30[]={ - {56,17}, -}; -const static huff_t table31[]={ - {54,17}, -}; -const static huff_t *huff_table[]={ - table0,table1,table2,table3,table4,table5,table6,table7,table8,table9,table10,table11,table12,table13,table14,table15,table16,table17,table18,table19,table20,table21,table22,table23,table24,table25,table26,table27,table28,table29,table30,table31, -}; -const static int maxlevel[]={ - 40,18,5,4,3,3,3,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -}; +const static huff_t table0[]={ + {6,3},{8,5},{10,6},{12,8},{76,9},{66,9},{20,11},{58,13},{48,13},{38,13},{32,13},{52,14},{50,14},{48,14},{46,14},{62,15},{60,15},{58,15},{56,15},{54,15},{52,15},{50,15},{48,15},{46,15},{44,15},{42,15},{40,15},{38,15},{36,15},{34,15},{32,15},{48,16},{46,16},{44,16},{42,16},{40,16},{38,16},{36,16},{34,16},{32,16}, +}; +const static huff_t table1[]={ + {6,4},{12,7},{74,9},{24,11},{54,13},{44,14},{42,14},{62,16},{60,16},{58,16},{56,16},{54,16},{52,16},{50,16},{38,17},{36,17},{34,17},{32,17}, +}; +const static huff_t table2[]={ + {10,5},{8,8},{22,11},{40,13},{40,14}, +}; +const static huff_t table3[]={ + {14,6},{72,9},{56,13},{38,14}, +}; +const static huff_t table4[]={ + {12,6},{30,11},{36,13}, +}; +const static huff_t table5[]={ + {14,7},{18,11},{36,14}, +}; +const static huff_t table6[]={ + {10,7},{60,13},{40,17}, +}; +const static huff_t table7[]={ + {8,7},{42,13}, +}; +const static huff_t table8[]={ + {14,8},{34,13}, +}; +const static huff_t table9[]={ + {10,8},{34,14}, +}; +const static huff_t table10[]={ + {78,9},{32,14}, +}; +const static huff_t table11[]={ + {70,9},{52,17}, +}; +const static huff_t table12[]={ + {68,9},{50,17}, +}; +const static huff_t table13[]={ + {64,9},{48,17}, +}; +const static huff_t table14[]={ + {28,11},{46,17}, +}; +const static huff_t table15[]={ + {26,11},{44,17}, +}; +const static huff_t table16[]={ + {16,11},{42,17}, +}; +const static huff_t table17[]={ + {62,13}, +}; +const static huff_t table18[]={ + {52,13}, +}; +const static huff_t table19[]={ + {50,13}, +}; +const static huff_t table20[]={ + {46,13}, +}; +const static huff_t table21[]={ + {44,13}, +}; +const static huff_t table22[]={ + {62,14}, +}; +const static huff_t table23[]={ + {60,14}, +}; +const static huff_t table24[]={ + {58,14}, +}; +const static huff_t table25[]={ + {56,14}, +}; +const static huff_t table26[]={ + {54,14}, +}; +const static huff_t table27[]={ + {62,17}, +}; +const static huff_t table28[]={ + {60,17}, +}; +const static huff_t table29[]={ + {58,17}, +}; +const static huff_t table30[]={ + {56,17}, +}; +const static huff_t table31[]={ + {54,17}, +}; +const static huff_t *huff_table[]={ + table0,table1,table2,table3,table4,table5,table6,table7,table8,table9,table10,table11,table12,table13,table14,table15,table16,table17,table18,table19,table20,table21,table22,table23,table24,table25,table26,table27,table28,table29,table30,table31, +}; +const static int maxlevel[]={ + 40,18,5,4,3,3,3,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +}; diff --git a/psxdev/vlc.c b/psxdev/vlc.c index aa7e610..780dcf1 100644 --- a/psxdev/vlc.c +++ b/psxdev/vlc.c @@ -1,602 +1,606 @@ -#include "bs.h" -#include - -#define SOFT - -#define CODE1(a,b,c) (((a)<<10)|((b)&0x3ff)|((c)<<16)) -/* run, level, bit */ -#define CODE(a,b,c) CODE1(a,b,c+1),CODE1(a,-b,c+1) -#define CODE0(a,b,c) CODE1(a,b,c),CODE1(a,b,c) -#define CODE2(a,b,c) CODE1(a,b,c+1),CODE1(a,b,c+1) -#define RUNOF(a) ((a)>>10) -#define VALOF(a) ((short)((a)<<6)>>6) -#define BITOF(a) ((a)>>16) -#define EOB 0xfe00 -#define ESCAPE_CODE CODE1(63,0,6) -#define EOB_CODE CODE1(63,512,2) - -/* - DC code - Y U,V -0 100 00 0 -1 00x 01x -1,1 -2 01xx 10xx -3,-2,2,3 -3 101xxx 110xxx -7..-4,4..7 -4 110xxxx 1110 -15..-8,8..15 -5 1110xxxxx 11110 -31..-16,16..31 -6 11110xxxxxx 111110 -63..-32,32..63 -7 111110 1111110 -127..-64,64..127 -8 1111110 11111110 -255..-128,128..255 - 7+8 8+8 -*/ - -/* - This table based on MPEG2DEC by MPEG Software Simulation Group -*/ - -/* Table B-14, DCT coefficients table zero, -* codes 0100 ... 1xxx (used for all other coefficients) -*/ -static const u_long VLCtabnext[12*2] = { - CODE(0,2,4), CODE(2,1,4), CODE2(1,1,3), CODE2(1,-1,3), - CODE0(63,512,2), CODE0(63,512,2), CODE0(63,512,2), CODE0(63,512,2), /*EOB*/ - CODE2(0,1,2), CODE2(0,1,2), CODE2(0,-1,2), CODE2(0,-1,2) -}; - -/* Table B-14, DCT coefficients table zero, -* codes 000001xx ... 00111xxx -*/ -static const u_long VLCtab0[60*2] = { - CODE0(63,0,6), CODE0(63,0,6),CODE0(63,0,6), CODE0(63,0,6), /* ESCAPE */ - CODE2(2,2,7), CODE2(2,-2,7), CODE2(9,1,7), CODE2(9,-1,7), - CODE2(0,4,7), CODE2(0,-4,7), CODE2(8,1,7), CODE2(8,-1,7), - CODE2(7,1,6), CODE2(7,1,6), CODE2(7,-1,6), CODE2(7,-1,6), - CODE2(6,1,6), CODE2(6,1,6), CODE2(6,-1,6), CODE2(6,-1,6), - CODE2(1,2,6), CODE2(1,2,6), CODE2(1,-2,6), CODE2(1,-2,6), - CODE2(5,1,6), CODE2(5,1,6), CODE2(5,-1,6), CODE2(5,-1,6), - CODE(13,1,8), CODE(0,6,8), CODE(12,1,8), CODE(11,1,8), - CODE(3,2,8), CODE(1,3,8), CODE(0,5,8), CODE(10,1,8), - CODE2(0,3,5), CODE2(0,3,5), CODE2(0,3,5), CODE2(0,3,5), - CODE2(0,-3,5), CODE2(0,-3,5), CODE2(0,-3,5), CODE2(0,-3,5), - CODE2(4,1,5), CODE2(4,1,5), CODE2(4,1,5), CODE2(4,1,5), - CODE2(4,-1,5), CODE2(4,-1,5), CODE2(4,-1,5), CODE2(4,-1,5), - CODE2(3,1,5), CODE2(3,1,5), CODE2(3,1,5), CODE2(3,1,5), - CODE2(3,-1,5), CODE2(3,-1,5), CODE2(3,-1,5), CODE2(3,-1,5) -}; - -/* Table B-14, DCT coefficients table zero, -* codes 0000001000 ... 0000001111 -*/ -static const u_long VLCtab1[8*2] = { - CODE(16,1,10), CODE(5,2,10), CODE(0,7,10), CODE(2,3,10), - CODE(1,4,10), CODE(15,1,10), CODE(14,1,10), CODE(4,2,10) -}; - -/* Table B-14/15, DCT coefficients table zero / one, -* codes 000000010000 ... 000000011111 -*/ -static const u_long VLCtab2[16*2] = { - CODE(0,11,12), CODE(8,2,12), CODE(4,3,12), CODE(0,10,12), - CODE(2,4,12), CODE(7,2,12), CODE(21,1,12), CODE(20,1,12), - CODE(0,9,12), CODE(19,1,12), CODE(18,1,12), CODE(1,5,12), - CODE(3,3,12), CODE(0,8,12), CODE(6,2,12), CODE(17,1,12) -}; - -/* Table B-14/15, DCT coefficients table zero / one, -* codes 0000000010000 ... 0000000011111 -*/ -static const u_long VLCtab3[16*2] = { - CODE(10,2,13), CODE(9,2,13), CODE(5,3,13), CODE(3,4,13), - CODE(2,5,13), CODE(1,7,13), CODE(1,6,13), CODE(0,15,13), - CODE(0,14,13), CODE(0,13,13), CODE(0,12,13), CODE(26,1,13), - CODE(25,1,13), CODE(24,1,13), CODE(23,1,13), CODE(22,1,13) -}; - -/* Table B-14/15, DCT coefficients table zero / one, -* codes 00000000010000 ... 00000000011111 -*/ -static const u_long VLCtab4[16*2] = { - CODE(0,31,14), CODE(0,30,14), CODE(0,29,14), CODE(0,28,14), - CODE(0,27,14), CODE(0,26,14), CODE(0,25,14), CODE(0,24,14), - CODE(0,23,14), CODE(0,22,14), CODE(0,21,14), CODE(0,20,14), - CODE(0,19,14), CODE(0,18,14), CODE(0,17,14), CODE(0,16,14) -}; - -/* Table B-14/15, DCT coefficients table zero / one, -* codes 000000000010000 ... 000000000011111 -*/ -static const u_long VLCtab5[16*2] = { - CODE(0,40,15), CODE(0,39,15), CODE(0,38,15), CODE(0,37,15), - CODE(0,36,15), CODE(0,35,15), CODE(0,34,15), CODE(0,33,15), - CODE(0,32,15), CODE(1,14,15), CODE(1,13,15), CODE(1,12,15), - CODE(1,11,15), CODE(1,10,15), CODE(1,9,15), CODE(1,8,15) -}; - -/* Table B-14/15, DCT coefficients table zero / one, -* codes 0000000000010000 ... 0000000000011111 -*/ -static const u_long VLCtab6[16*2] = { - CODE(1,18,16), CODE(1,17,16), CODE(1,16,16), CODE(1,15,16), - CODE(6,3,16), CODE(16,2,16), CODE(15,2,16), CODE(14,2,16), - CODE(13,2,16), CODE(12,2,16), CODE(11,2,16), CODE(31,1,16), - CODE(30,1,16), CODE(29,1,16), CODE(28,1,16), CODE(27,1,16) -}; - -/* - DC code - Y U,V -0 100 00 0 -1 00x 01x -1,1 -2 01xx 10xx -3,-2,2,3 -3 101xxx 110xxx -7..-4,4..7 -4 110xxxx 1110xxxx -15..-8,8..15 -5 1110xxxxx 11110xxxxx -31..-16,16..31 -6 11110xxxxxx 111110xxxxxx -63..-32,32..63 -7 111110xxxxxxx 1111110xxxxxxx -127..-64,64..127 -8 1111110xxxxxxxx 11111110xxxxxxxx -255..-128,128..255 -*/ - -static const u_long DC_Ytab0[48] = { - CODE1(0,-1,3),CODE1(0,-1,3),CODE1(0,-1,3),CODE1(0,-1,3), - CODE1(0,-1,3),CODE1(0,-1,3),CODE1(0,-1,3),CODE1(0,-1,3), - CODE1(0,1,3),CODE1(0,1,3),CODE1(0,1,3),CODE1(0,1,3), - CODE1(0,1,3),CODE1(0,1,3),CODE1(0,1,3),CODE1(0,1,3), - - CODE1(0,-3,4),CODE1(0,-3,4),CODE1(0,-3,4),CODE1(0,-3,4), - CODE1(0,-2,4),CODE1(0,-2,4),CODE1(0,-2,4),CODE1(0,-2,4), - CODE1(0,2,4),CODE1(0,2,4),CODE1(0,2,4),CODE1(0,2,4), - CODE1(0,3,4),CODE1(0,3,4),CODE1(0,3,4),CODE1(0,3,4), - - CODE1(0,0,3),CODE1(0,0,3),CODE1(0,0,3),CODE1(0,0,3), - CODE1(0,0,3),CODE1(0,0,3),CODE1(0,0,3),CODE1(0,0,3), - CODE1(0,-7,6),CODE1(0,-6,6),CODE1(0,-5,6),CODE1(0,-4,6), - CODE1(0,4,6),CODE1(0,5,6),CODE1(0,6,6),CODE1(0,7,6), - -}; - -static const u_long DC_UVtab0[56] = { - CODE1(0,0,2),CODE1(0,0,2),CODE1(0,0,2),CODE1(0,0,2), - CODE1(0,0,2),CODE1(0,0,2),CODE1(0,0,2),CODE1(0,0,2), - CODE1(0,0,2),CODE1(0,0,2),CODE1(0,0,2),CODE1(0,0,2), - CODE1(0,0,2),CODE1(0,0,2),CODE1(0,0,2),CODE1(0,0,2), - - CODE1(0,-1,3),CODE1(0,-1,3),CODE1(0,-1,3),CODE1(0,-1,3), - CODE1(0,-1,3),CODE1(0,-1,3),CODE1(0,-1,3),CODE1(0,-1,3), - CODE1(0,1,3),CODE1(0,1,3),CODE1(0,1,3),CODE1(0,1,3), - CODE1(0,1,3),CODE1(0,1,3),CODE1(0,1,3),CODE1(0,1,3), - - CODE1(0,-3,4),CODE1(0,-3,4),CODE1(0,-3,4),CODE1(0,-3,4), - CODE1(0,-2,4),CODE1(0,-2,4),CODE1(0,-2,4),CODE1(0,-2,4), - CODE1(0,2,4),CODE1(0,2,4),CODE1(0,2,4),CODE1(0,2,4), - CODE1(0,3,4),CODE1(0,3,4),CODE1(0,3,4),CODE1(0,3,4), - - CODE1(0,-7,6),CODE1(0,-6,6),CODE1(0,-5,6),CODE1(0,-4,6), - CODE1(0,4,6),CODE1(0,5,6),CODE1(0,6,6),CODE1(0,7,6), -}; - -#define DCTSIZE2 64 - -/* decode one intra coded MPEG-1 block */ - -#define Show_Bits(N) (bitbuf>>(32-(N))) -/* 最小有効bit 17 bit*/ - -#define Flush_Buffer(N) {bitbuf <<=(N);incnt +=(N);while(incnt>=0) {bitbuf |= Get_Word()<=2) { - /* Y */ - if (code2<48) { - code2 = DC_Ytab0[code2]; - code2 = (code2&0xffff0000)|((last_dc[2]+=VALOF(code2)*4)&0x3ff); - } else { - int nbit,val; - int bit = 3; - while(Show_Bits(bit)&1) { bit++;} - bit++; - nbit = bit*2-1; - val = Show_Bits(nbit)&((1<=1<<(SBIT- 2)) { - code2 = VLCtabnext[(code>>12)-8]; - if (code2==EOB_CODE) break; - } - else if (code>=1<<(SBIT- 6)) { - code2 = VLCtab0[(code>>8)-8]; - if (code2==ESCAPE_CODE) { - Flush_Buffer(6); /* ESCAPE len */ - code2 = Show_Bits(16)| (16<<16); - } - } - else if (code>=1<<(SBIT- 7)) code2 = VLCtab1[(code>>6)-16]; - else if (code>=1<<(SBIT- 8)) code2 = VLCtab2[(code>>4)-32]; - else if (code>=1<<(SBIT- 9)) code2 = VLCtab3[(code>>3)-32]; - else if (code>=1<<(SBIT-10)) code2 = VLCtab4[(code>>2)-32]; - else if (code>=1<<(SBIT-11)) code2 = VLCtab5[(code>>1)-32]; - else if (code>=1<<(SBIT-12)) code2 = VLCtab6[(code>>0)-32]; - else { - do { - *mdec_rl++=EOB; - } while(mdec_rliqtab[i] =ctxt->iq_y[i]*aanscales[i]>>(CONST_BITS-IFAST_SCALE_BITS); - } -} - -#define BLOCK long - -extern IDCT(BLOCK *blk,int k); - -u_short* rl2blk(bs_context_t *ctxt, BLOCK *blk,u_short *mdec_rl) -{ - int i,k,q_scale,rl; - memset(blk,0,6*DCTSIZE2*sizeof(BLOCK)); - for(i=0;i<6;i++) { - rl = *mdec_rl++; - q_scale = RUNOF(rl); - blk[0] = ctxt->iqtab[0]*VALOF(rl); - k = 0; - for(;;) { - rl = *mdec_rl++; - if (rl==EOB) break; - k += RUNOF(rl)+1; - blk[zscan[k]] = ctxt->iqtab[zscan[k]]*q_scale*VALOF(rl)/8; - } - - IDCT(blk,k+1); - - blk+=DCTSIZE2; - } - return mdec_rl; -} - -#define RGB15(r,g,b) ( (((b)&0xf8)<<7)|(((g)&0xf8)<<2)|((r)>>3) ) - -#define ROUND(r) bs_roundtbl[(r)+256] -#if 1 -#define SHIFT 12 -#define toFIX(a) (int)((a)*(1<>SHIFT) -#define FIX_1 toFIX(1) -#define MULR(a) toINT((a)*toFIX(1.402)) -#define MULG(a) toINT((a)*toFIX(-0.3437)) -#define MULG2(a) toINT((a)*toFIX(-0.7143)) -#define MULB(a) toINT((a)*toFIX(1.772)) -#else -#define MULR(a) 0 -#define MULG(a) 0 -#define MULG2(a) 0 -#define MULB(a) 0 -#endif - - -/* -int ROUND(int r) -{ - if (r<0) return 0; - else if (r>255) return 255; - else return r; -} -*/ - -extern u_char bs_roundtbl[256*3]; - -static void yuv2rgb15(BLOCK *blk,u_short *image) -{ - int x,yy; - BLOCK *yblk = blk+DCTSIZE2*2; - for(yy=0;yy<16;yy+=2,blk+=4,yblk+=8,image+=8+16) { - if (yy==8) yblk+=DCTSIZE2; - for(x=0;x<4;x++,blk++,yblk+=2,image+=2) { - int r0,b0,g0,y; - r0 = MULR(blk[DCTSIZE2]); /* cr */ - g0 = MULG(blk[0])+MULG2(blk[DCTSIZE2]); - b0 = MULB(blk[0]); /* cb */ - y = yblk[0]+128; - image[0] = RGB15(ROUND(r0+y),ROUND(g0+y),ROUND(b0+y)); - y = yblk[1]+128+4; - image[1] = RGB15(ROUND(r0+y),ROUND(g0+y),ROUND(b0+y)); - y = yblk[8]+128+6; - image[16] = RGB15(ROUND(r0+y),ROUND(g0+y),ROUND(b0+y)); - y = yblk[9]+128+2; - image[17] = RGB15(ROUND(r0+y),ROUND(g0+y),ROUND(b0+y)); - r0 = MULR(blk[4+DCTSIZE2]); - g0 = MULG(blk[4])+MULG2(blk[4+DCTSIZE2]); - b0 = MULB(blk[4]); - y = yblk[DCTSIZE2+0]+128; - image[8+0] = RGB15(ROUND(r0+y),ROUND(g0+y),ROUND(b0+y)); - y = yblk[DCTSIZE2+1]+128+4; - image[8+1] = RGB15(ROUND(r0+y),ROUND(g0+y),ROUND(b0+y)); - y = yblk[DCTSIZE2+8]+128+6; - image[8+16] = RGB15(ROUND(r0+y),ROUND(g0+y),ROUND(b0+y)); - y = yblk[DCTSIZE2+9]+128+2; - image[8+17] = RGB15(ROUND(r0+y),ROUND(g0+y),ROUND(b0+y)); - } - } -} - -enum {B,G,R}; - -static void yuv2rgb24(BLOCK *blk,u_char image[][3]) -{ - int x,yy; - BLOCK *yblk = blk+DCTSIZE2*2; - for(yy=0;yy<16;yy+=2,blk+=4,yblk+=8,image+=8+16) { - if (yy==8) yblk+=DCTSIZE2; - for(x=0;x<4;x++,blk++,yblk+=2,image+=2) { - int r0,b0,g0,y; - r0 = MULR(blk[DCTSIZE2]); /* cr */ - g0 = MULG(blk[0])+MULG2(blk[DCTSIZE2]); - b0 = MULB(blk[0]); /* cb */ - y = yblk[0]+128; - image[0][R] = ROUND(r0+y); - image[0][G] = ROUND(g0+y); - image[0][B] = ROUND(b0+y); - y = yblk[1]+128; - image[1][R] = ROUND(r0+y); - image[1][G] = ROUND(g0+y); - image[1][B] = ROUND(b0+y); - y = yblk[8]+128; - image[16][R] = ROUND(r0+y); - image[16][G] = ROUND(g0+y); - image[16][B] = ROUND(b0+y); - y = yblk[9]+128; - image[17][R] = ROUND(r0+y); - image[17][G] = ROUND(g0+y); - image[17][B] = ROUND(b0+y); - - r0 = MULR(blk[4+DCTSIZE2]); - g0 = MULG(blk[4])+MULG2(blk[4+DCTSIZE2]); - b0 = MULB(blk[4]); - y = yblk[DCTSIZE2+0]+128; - image[8+0][R] = ROUND(r0+y); - image[8+0][G] = ROUND(g0+y); - image[8+0][B] = ROUND(b0+y); - y = yblk[DCTSIZE2+1]+128; - image[8+1][R] = ROUND(r0+y); - image[8+1][G] = ROUND(g0+y); - image[8+1][B] = ROUND(b0+y); - y = yblk[DCTSIZE2+8]+128; - image[8+16][R] = ROUND(r0+y); - image[8+16][G] = ROUND(g0+y); - image[8+16][B] = ROUND(b0+y); - y = yblk[DCTSIZE2+9]+128; - image[8+17][R] = ROUND(r0+y); - image[8+17][G] = ROUND(g0+y); - image[8+17][B] = ROUND(b0+y); - } - } -} - -static void DecDCTReset(bs_context_t *ctxt, int mode) -{ - iqtab_init(ctxt); -} - -static void DecDCTin(bs_context_t *ctxt, u_short *mdecrl,int mode) -{ - mdecrl+=2; - ctxt->mdec_rl = mdecrl; - ctxt->rl_end = mdecrl+mdecrl[-2]*2; - ctxt->mdec_mode = mode; -} - -static void DecDCTout(bs_context_t *ctxt, u_short *image,int size) -{ - BLOCK blk[DCTSIZE2*6]; - int blocksize=16*16; - if (ctxt->mdec_mode) blocksize = 16*16*3/2; - for(;size>0;size-=blocksize/2,image+=blocksize) { - ctxt->mdec_rl = rl2blk(ctxt,blk,ctxt->mdec_rl); - if (ctxt->mdec_mode==0) yuv2rgb15(blk,image); - else yuv2rgb24(blk,image); - } -} - -void bs_decode_rgb24 ( - unsigned char *outbuf, // output RGB bytes (width*height*3) - bs_header_t *img, // input BS image - int width, int height, // dimension of BS image - unsigned char *myiqtab - ) -{ - unsigned short *buf2 = (unsigned short *) outbuf; - unsigned short *bufp = (unsigned short *) img; - bs_context_t ctxt; - unsigned short *rl,*image; - int slice,rlsize; - int mode; - int x,y; - int height2 = (height+15)&~15; - int w; - - ctxt.iq_y = myiqtab ? myiqtab : bs_iqtab(); - mode=1; - w=24; - width = width*3/2; - - image = (unsigned short *) malloc (height2*w*sizeof(short)); - rl = (unsigned short *) malloc ((bufp[0]+2)*sizeof(long)); - - DecDCTReset(&ctxt,0); - DecDCTvlc(bufp,rl); - DecDCTin(&ctxt,rl,mode); - - slice = height2*w/2; - - for(x=0;x=0;y--) - { - memcpy(dst,src,w*2); - src+=w; - dst+=width; - } - } - - free (image); - free (rl); -} - -void bs_decode_rgb15 ( - unsigned short *outbuf, // output RGB bytes (width*height*2) - bs_header_t *img, // input BS image - int width, int height, // dimension of BS image - unsigned char *myiqtab - ) -{ - unsigned short *buf2 = (unsigned short *) outbuf; - unsigned short *bufp = (unsigned short *) img; - bs_context_t ctxt; - unsigned short *rl,*image; - int slice,rlsize; - int mode; - int x,y; - int height2 = (height+15)&~15; - int w; - - ctxt.iq_y = myiqtab ? myiqtab : bs_iqtab(); - mode=0; - w=24; - - image = (unsigned short *) malloc (height2*w*sizeof(short)); - rl = (unsigned short *) malloc ((bufp[0]+2)*sizeof(long)); - - DecDCTReset(&ctxt,0); - DecDCTvlc(bufp,rl); - DecDCTin(&ctxt,rl,mode); - - slice = height2*w/2; - - for(x=0;x=0;y--) - { - memcpy(dst,src,w*2); - src+=w; - dst-=width; - } - } - - free (image); - free (rl); -} +#include "bs.h" +#include +#include +#include + +#define SOFT + +#define CODE1(a,b,c) (((a)<<10)|((b)&0x3ff)|((c)<<16)) +/* run, level, bit */ +#define CODE(a,b,c) CODE1(a,b,c+1),CODE1(a,-b,c+1) +#define CODE0(a,b,c) CODE1(a,b,c),CODE1(a,b,c) +#define CODE2(a,b,c) CODE1(a,b,c+1),CODE1(a,b,c+1) +#define RUNOF(a) ((a)>>10) +#define VALOF(a) ((short)((a)<<6)>>6) +#define BITOF(a) ((a)>>16) +#define EOB 0xfe00 +#define ESCAPE_CODE CODE1(63,0,6) +#define EOB_CODE CODE1(63,512,2) + +/* + DC code + Y U,V +0 100 00 0 +1 00x 01x -1,1 +2 01xx 10xx -3,-2,2,3 +3 101xxx 110xxx -7..-4,4..7 +4 110xxxx 1110 -15..-8,8..15 +5 1110xxxxx 11110 -31..-16,16..31 +6 11110xxxxxx 111110 -63..-32,32..63 +7 111110 1111110 -127..-64,64..127 +8 1111110 11111110 -255..-128,128..255 + 7+8 8+8 +*/ + +/* + This table based on MPEG2DEC by MPEG Software Simulation Group +*/ + +/* Table B-14, DCT coefficients table zero, +* codes 0100 ... 1xxx (used for all other coefficients) +*/ +static const u_long VLCtabnext[12*2] = { + CODE(0,2,4), CODE(2,1,4), CODE2(1,1,3), CODE2(1,-1,3), + CODE0(63,512,2), CODE0(63,512,2), CODE0(63,512,2), CODE0(63,512,2), /*EOB*/ + CODE2(0,1,2), CODE2(0,1,2), CODE2(0,-1,2), CODE2(0,-1,2) +}; + +/* Table B-14, DCT coefficients table zero, +* codes 000001xx ... 00111xxx +*/ +static const u_long VLCtab0[60*2] = { + CODE0(63,0,6), CODE0(63,0,6),CODE0(63,0,6), CODE0(63,0,6), /* ESCAPE */ + CODE2(2,2,7), CODE2(2,-2,7), CODE2(9,1,7), CODE2(9,-1,7), + CODE2(0,4,7), CODE2(0,-4,7), CODE2(8,1,7), CODE2(8,-1,7), + CODE2(7,1,6), CODE2(7,1,6), CODE2(7,-1,6), CODE2(7,-1,6), + CODE2(6,1,6), CODE2(6,1,6), CODE2(6,-1,6), CODE2(6,-1,6), + CODE2(1,2,6), CODE2(1,2,6), CODE2(1,-2,6), CODE2(1,-2,6), + CODE2(5,1,6), CODE2(5,1,6), CODE2(5,-1,6), CODE2(5,-1,6), + CODE(13,1,8), CODE(0,6,8), CODE(12,1,8), CODE(11,1,8), + CODE(3,2,8), CODE(1,3,8), CODE(0,5,8), CODE(10,1,8), + CODE2(0,3,5), CODE2(0,3,5), CODE2(0,3,5), CODE2(0,3,5), + CODE2(0,-3,5), CODE2(0,-3,5), CODE2(0,-3,5), CODE2(0,-3,5), + CODE2(4,1,5), CODE2(4,1,5), CODE2(4,1,5), CODE2(4,1,5), + CODE2(4,-1,5), CODE2(4,-1,5), CODE2(4,-1,5), CODE2(4,-1,5), + CODE2(3,1,5), CODE2(3,1,5), CODE2(3,1,5), CODE2(3,1,5), + CODE2(3,-1,5), CODE2(3,-1,5), CODE2(3,-1,5), CODE2(3,-1,5) +}; + +/* Table B-14, DCT coefficients table zero, +* codes 0000001000 ... 0000001111 +*/ +static const u_long VLCtab1[8*2] = { + CODE(16,1,10), CODE(5,2,10), CODE(0,7,10), CODE(2,3,10), + CODE(1,4,10), CODE(15,1,10), CODE(14,1,10), CODE(4,2,10) +}; + +/* Table B-14/15, DCT coefficients table zero / one, +* codes 000000010000 ... 000000011111 +*/ +static const u_long VLCtab2[16*2] = { + CODE(0,11,12), CODE(8,2,12), CODE(4,3,12), CODE(0,10,12), + CODE(2,4,12), CODE(7,2,12), CODE(21,1,12), CODE(20,1,12), + CODE(0,9,12), CODE(19,1,12), CODE(18,1,12), CODE(1,5,12), + CODE(3,3,12), CODE(0,8,12), CODE(6,2,12), CODE(17,1,12) +}; + +/* Table B-14/15, DCT coefficients table zero / one, +* codes 0000000010000 ... 0000000011111 +*/ +static const u_long VLCtab3[16*2] = { + CODE(10,2,13), CODE(9,2,13), CODE(5,3,13), CODE(3,4,13), + CODE(2,5,13), CODE(1,7,13), CODE(1,6,13), CODE(0,15,13), + CODE(0,14,13), CODE(0,13,13), CODE(0,12,13), CODE(26,1,13), + CODE(25,1,13), CODE(24,1,13), CODE(23,1,13), CODE(22,1,13) +}; + +/* Table B-14/15, DCT coefficients table zero / one, +* codes 00000000010000 ... 00000000011111 +*/ +static const u_long VLCtab4[16*2] = { + CODE(0,31,14), CODE(0,30,14), CODE(0,29,14), CODE(0,28,14), + CODE(0,27,14), CODE(0,26,14), CODE(0,25,14), CODE(0,24,14), + CODE(0,23,14), CODE(0,22,14), CODE(0,21,14), CODE(0,20,14), + CODE(0,19,14), CODE(0,18,14), CODE(0,17,14), CODE(0,16,14) +}; + +/* Table B-14/15, DCT coefficients table zero / one, +* codes 000000000010000 ... 000000000011111 +*/ +static const u_long VLCtab5[16*2] = { + CODE(0,40,15), CODE(0,39,15), CODE(0,38,15), CODE(0,37,15), + CODE(0,36,15), CODE(0,35,15), CODE(0,34,15), CODE(0,33,15), + CODE(0,32,15), CODE(1,14,15), CODE(1,13,15), CODE(1,12,15), + CODE(1,11,15), CODE(1,10,15), CODE(1,9,15), CODE(1,8,15) +}; + +/* Table B-14/15, DCT coefficients table zero / one, +* codes 0000000000010000 ... 0000000000011111 +*/ +static const u_long VLCtab6[16*2] = { + CODE(1,18,16), CODE(1,17,16), CODE(1,16,16), CODE(1,15,16), + CODE(6,3,16), CODE(16,2,16), CODE(15,2,16), CODE(14,2,16), + CODE(13,2,16), CODE(12,2,16), CODE(11,2,16), CODE(31,1,16), + CODE(30,1,16), CODE(29,1,16), CODE(28,1,16), CODE(27,1,16) +}; + +/* + DC code + Y U,V +0 100 00 0 +1 00x 01x -1,1 +2 01xx 10xx -3,-2,2,3 +3 101xxx 110xxx -7..-4,4..7 +4 110xxxx 1110xxxx -15..-8,8..15 +5 1110xxxxx 11110xxxxx -31..-16,16..31 +6 11110xxxxxx 111110xxxxxx -63..-32,32..63 +7 111110xxxxxxx 1111110xxxxxxx -127..-64,64..127 +8 1111110xxxxxxxx 11111110xxxxxxxx -255..-128,128..255 +*/ + +static const u_long DC_Ytab0[48] = { + CODE1(0,-1,3),CODE1(0,-1,3),CODE1(0,-1,3),CODE1(0,-1,3), + CODE1(0,-1,3),CODE1(0,-1,3),CODE1(0,-1,3),CODE1(0,-1,3), + CODE1(0,1,3),CODE1(0,1,3),CODE1(0,1,3),CODE1(0,1,3), + CODE1(0,1,3),CODE1(0,1,3),CODE1(0,1,3),CODE1(0,1,3), + + CODE1(0,-3,4),CODE1(0,-3,4),CODE1(0,-3,4),CODE1(0,-3,4), + CODE1(0,-2,4),CODE1(0,-2,4),CODE1(0,-2,4),CODE1(0,-2,4), + CODE1(0,2,4),CODE1(0,2,4),CODE1(0,2,4),CODE1(0,2,4), + CODE1(0,3,4),CODE1(0,3,4),CODE1(0,3,4),CODE1(0,3,4), + + CODE1(0,0,3),CODE1(0,0,3),CODE1(0,0,3),CODE1(0,0,3), + CODE1(0,0,3),CODE1(0,0,3),CODE1(0,0,3),CODE1(0,0,3), + CODE1(0,-7,6),CODE1(0,-6,6),CODE1(0,-5,6),CODE1(0,-4,6), + CODE1(0,4,6),CODE1(0,5,6),CODE1(0,6,6),CODE1(0,7,6), + +}; + +static const u_long DC_UVtab0[56] = { + CODE1(0,0,2),CODE1(0,0,2),CODE1(0,0,2),CODE1(0,0,2), + CODE1(0,0,2),CODE1(0,0,2),CODE1(0,0,2),CODE1(0,0,2), + CODE1(0,0,2),CODE1(0,0,2),CODE1(0,0,2),CODE1(0,0,2), + CODE1(0,0,2),CODE1(0,0,2),CODE1(0,0,2),CODE1(0,0,2), + + CODE1(0,-1,3),CODE1(0,-1,3),CODE1(0,-1,3),CODE1(0,-1,3), + CODE1(0,-1,3),CODE1(0,-1,3),CODE1(0,-1,3),CODE1(0,-1,3), + CODE1(0,1,3),CODE1(0,1,3),CODE1(0,1,3),CODE1(0,1,3), + CODE1(0,1,3),CODE1(0,1,3),CODE1(0,1,3),CODE1(0,1,3), + + CODE1(0,-3,4),CODE1(0,-3,4),CODE1(0,-3,4),CODE1(0,-3,4), + CODE1(0,-2,4),CODE1(0,-2,4),CODE1(0,-2,4),CODE1(0,-2,4), + CODE1(0,2,4),CODE1(0,2,4),CODE1(0,2,4),CODE1(0,2,4), + CODE1(0,3,4),CODE1(0,3,4),CODE1(0,3,4),CODE1(0,3,4), + + CODE1(0,-7,6),CODE1(0,-6,6),CODE1(0,-5,6),CODE1(0,-4,6), + CODE1(0,4,6),CODE1(0,5,6),CODE1(0,6,6),CODE1(0,7,6), +}; + +#define DCTSIZE2 64 + +/* decode one intra coded MPEG-1 block */ + +#define Show_Bits(N) (bitbuf>>(32-(N))) +/* 最小有効bit 17 bit*/ + +#define Flush_Buffer(N) {bitbuf <<=(N);incnt +=(N);while(incnt>=0) {bitbuf |= Get_Word()<=2) { + /* Y */ + if (code2<48) { + code2 = DC_Ytab0[code2]; + code2 = (code2&0xffff0000)|((last_dc[2]+=VALOF(code2)*4)&0x3ff); + } else { + int nbit,val; + int bit = 3; + while(Show_Bits(bit)&1) { bit++;} + bit++; + nbit = bit*2-1; + val = Show_Bits(nbit)&((1<=1<<(SBIT- 2)) { + code2 = VLCtabnext[(code>>12)-8]; + if (code2==EOB_CODE) break; + } + else if (code>=1<<(SBIT- 6)) { + code2 = VLCtab0[(code>>8)-8]; + if (code2==ESCAPE_CODE) { + Flush_Buffer(6); /* ESCAPE len */ + code2 = Show_Bits(16)| (16<<16); + } + } + else if (code>=1<<(SBIT- 7)) code2 = VLCtab1[(code>>6)-16]; + else if (code>=1<<(SBIT- 8)) code2 = VLCtab2[(code>>4)-32]; + else if (code>=1<<(SBIT- 9)) code2 = VLCtab3[(code>>3)-32]; + else if (code>=1<<(SBIT-10)) code2 = VLCtab4[(code>>2)-32]; + else if (code>=1<<(SBIT-11)) code2 = VLCtab5[(code>>1)-32]; + else if (code>=1<<(SBIT-12)) code2 = VLCtab6[(code>>0)-32]; + else { + do { + *mdec_rl++=EOB; + } while(mdec_rliqtab[i] =ctxt->iq_y[i]*aanscales[i]>>(CONST_BITS-IFAST_SCALE_BITS); + } +} + +#define BLOCK long + +extern void IDCT(BLOCK *blk,int k); + +u_short* rl2blk(bs_context_t *ctxt, BLOCK *blk,u_short *mdec_rl) +{ + int i,k,q_scale,rl; + memset(blk,0,6*DCTSIZE2*sizeof(BLOCK)); + for(i=0;i<6;i++) { + rl = *mdec_rl++; + q_scale = RUNOF(rl); + blk[0] = ctxt->iqtab[0]*VALOF(rl); + k = 0; + for(;;) { + rl = *mdec_rl++; + if (rl==EOB) break; + k += RUNOF(rl)+1; + blk[zscan[k]] = ctxt->iqtab[zscan[k]]*q_scale*VALOF(rl)/8; + } + + IDCT(blk,k+1); + + blk+=DCTSIZE2; + } + return mdec_rl; +} + +#define RGB15(r,g,b) ( (((b)&0xf8)<<7)|(((g)&0xf8)<<2)|((r)>>3) ) + +#define ROUND(r) bs_roundtbl[(r)+256] +#if 1 +#define SHIFT 12 +#define toFIX(a) (int)((a)*(1<>SHIFT) +#define FIX_1 toFIX(1) +#define MULR(a) toINT((a)*toFIX(1.402)) +#define MULG(a) toINT((a)*toFIX(-0.3437)) +#define MULG2(a) toINT((a)*toFIX(-0.7143)) +#define MULB(a) toINT((a)*toFIX(1.772)) +#else +#define MULR(a) 0 +#define MULG(a) 0 +#define MULG2(a) 0 +#define MULB(a) 0 +#endif + + +/* +int ROUND(int r) +{ + if (r<0) return 0; + else if (r>255) return 255; + else return r; +} +*/ + +extern u_char bs_roundtbl[256*3]; + +static void yuv2rgb15(BLOCK *blk,u_short *image) +{ + int x,yy; + BLOCK *yblk = blk+DCTSIZE2*2; + for(yy=0;yy<16;yy+=2,blk+=4,yblk+=8,image+=8+16) { + if (yy==8) yblk+=DCTSIZE2; + for(x=0;x<4;x++,blk++,yblk+=2,image+=2) { + int r0,b0,g0,y; + r0 = MULR(blk[DCTSIZE2]); /* cr */ + g0 = MULG(blk[0])+MULG2(blk[DCTSIZE2]); + b0 = MULB(blk[0]); /* cb */ + y = yblk[0]+128; + image[0] = RGB15(ROUND(r0+y),ROUND(g0+y),ROUND(b0+y)); + y = yblk[1]+128+4; + image[1] = RGB15(ROUND(r0+y),ROUND(g0+y),ROUND(b0+y)); + y = yblk[8]+128+6; + image[16] = RGB15(ROUND(r0+y),ROUND(g0+y),ROUND(b0+y)); + y = yblk[9]+128+2; + image[17] = RGB15(ROUND(r0+y),ROUND(g0+y),ROUND(b0+y)); + r0 = MULR(blk[4+DCTSIZE2]); + g0 = MULG(blk[4])+MULG2(blk[4+DCTSIZE2]); + b0 = MULB(blk[4]); + y = yblk[DCTSIZE2+0]+128; + image[8+0] = RGB15(ROUND(r0+y),ROUND(g0+y),ROUND(b0+y)); + y = yblk[DCTSIZE2+1]+128+4; + image[8+1] = RGB15(ROUND(r0+y),ROUND(g0+y),ROUND(b0+y)); + y = yblk[DCTSIZE2+8]+128+6; + image[8+16] = RGB15(ROUND(r0+y),ROUND(g0+y),ROUND(b0+y)); + y = yblk[DCTSIZE2+9]+128+2; + image[8+17] = RGB15(ROUND(r0+y),ROUND(g0+y),ROUND(b0+y)); + } + } +} + +enum {B,G,R}; + +static void yuv2rgb24(BLOCK *blk,u_char image[][3]) +{ + int x,yy; + BLOCK *yblk = blk+DCTSIZE2*2; + for(yy=0;yy<16;yy+=2,blk+=4,yblk+=8,image+=8+16) { + if (yy==8) yblk+=DCTSIZE2; + for(x=0;x<4;x++,blk++,yblk+=2,image+=2) { + int r0,b0,g0,y; + r0 = MULR(blk[DCTSIZE2]); /* cr */ + g0 = MULG(blk[0])+MULG2(blk[DCTSIZE2]); + b0 = MULB(blk[0]); /* cb */ + y = yblk[0]+128; + image[0][R] = ROUND(r0+y); + image[0][G] = ROUND(g0+y); + image[0][B] = ROUND(b0+y); + y = yblk[1]+128; + image[1][R] = ROUND(r0+y); + image[1][G] = ROUND(g0+y); + image[1][B] = ROUND(b0+y); + y = yblk[8]+128; + image[16][R] = ROUND(r0+y); + image[16][G] = ROUND(g0+y); + image[16][B] = ROUND(b0+y); + y = yblk[9]+128; + image[17][R] = ROUND(r0+y); + image[17][G] = ROUND(g0+y); + image[17][B] = ROUND(b0+y); + + r0 = MULR(blk[4+DCTSIZE2]); + g0 = MULG(blk[4])+MULG2(blk[4+DCTSIZE2]); + b0 = MULB(blk[4]); + y = yblk[DCTSIZE2+0]+128; + image[8+0][R] = ROUND(r0+y); + image[8+0][G] = ROUND(g0+y); + image[8+0][B] = ROUND(b0+y); + y = yblk[DCTSIZE2+1]+128; + image[8+1][R] = ROUND(r0+y); + image[8+1][G] = ROUND(g0+y); + image[8+1][B] = ROUND(b0+y); + y = yblk[DCTSIZE2+8]+128; + image[8+16][R] = ROUND(r0+y); + image[8+16][G] = ROUND(g0+y); + image[8+16][B] = ROUND(b0+y); + y = yblk[DCTSIZE2+9]+128; + image[8+17][R] = ROUND(r0+y); + image[8+17][G] = ROUND(g0+y); + image[8+17][B] = ROUND(b0+y); + } + } +} + +static void DecDCTReset(bs_context_t *ctxt, int mode) +{ + iqtab_init(ctxt); +} + +static void DecDCTin(bs_context_t *ctxt, u_short *mdecrl,int mode) +{ + mdecrl+=2; + ctxt->mdec_rl = mdecrl; + ctxt->rl_end = mdecrl+mdecrl[-2]*2; + ctxt->mdec_mode = mode; +} + +static void DecDCTout(bs_context_t *ctxt, u_short *image,int size) +{ + BLOCK blk[DCTSIZE2*6]; + int blocksize=16*16; + if (ctxt->mdec_mode) blocksize = 16*16*3/2; + for(;size>0;size-=blocksize/2,image+=blocksize) { + ctxt->mdec_rl = rl2blk(ctxt,blk,ctxt->mdec_rl); + if (ctxt->mdec_mode==0) yuv2rgb15(blk,image); + else yuv2rgb24(blk,image); + } +} + +void bs_decode_rgb24 ( + unsigned char *outbuf, /* output RGB bytes (width*height*3) */ + bs_header_t *img, /* input BS image */ + int width, int height, /* dimension of BS image */ + const unsigned char *myiqtab + ) +{ + unsigned short *buf2 = (unsigned short *) outbuf; + unsigned short *bufp = (unsigned short *) img; + bs_context_t ctxt; + unsigned short *rl,*image; + int slice; + /* int rlsize; */ + int mode; + int x,y; + int height2 = (height+15)&~15; + int w; + + ctxt.iq_y = myiqtab ? myiqtab : bs_iqtab(); + mode=1; + w=24; + width = width*3/2; + + image = (unsigned short *) malloc (height2*w*sizeof(short)); + rl = (unsigned short *) malloc ((bufp[0]+2)*sizeof(long)); + + DecDCTReset(&ctxt,0); + DecDCTvlc(bufp,rl); + DecDCTin(&ctxt,rl,mode); + + slice = height2*w/2; + + for(x=0;x=0;y--) + { + memcpy(dst,src,w*2); + src+=w; + dst+=width; + } + } + + free (image); + free (rl); +} + +void bs_decode_rgb15 ( + unsigned short *outbuf, /* output RGB bytes (width*height*2) */ + bs_header_t *img, /* input BS image */ + int width, int height, /* dimension of BS image */ + const unsigned char *myiqtab + ) +{ + unsigned short *buf2 = (unsigned short *) outbuf; + unsigned short *bufp = (unsigned short *) img; + bs_context_t ctxt; + unsigned short *rl,*image; + int slice; + /* int rlsize; */ + int mode; + int x,y; + int height2 = (height+15)&~15; + int w; + + ctxt.iq_y = myiqtab ? myiqtab : bs_iqtab(); + mode=0; + w=24; + + image = (unsigned short *) malloc (height2*w*sizeof(short)); + rl = (unsigned short *) malloc ((bufp[0]+2)*sizeof(long)); + + DecDCTReset(&ctxt,0); + DecDCTvlc(bufp,rl); + DecDCTin(&ctxt,rl,mode); + + slice = height2*w/2; + + for(x=0;x=0;y--) + { + memcpy(dst,src,w*2); + src+=w; + dst-=width; + } + } + + free (image); + free (rl); +} diff --git a/psxdev/xadecode.c b/psxdev/xadecode.c new file mode 100644 index 0000000..682b42c --- /dev/null +++ b/psxdev/xadecode.c @@ -0,0 +1,301 @@ +/* + author: unknown, probably bitmaster? + slightly modified by dbalster +*/ + +#include +#include +#include +#include +#include "xadecode.h" + +#if USE_FXD +static FXD K0[4] = { + 0x00000000, + 0x0000F000, + 0x0001CC00, + 0x00018800 +}; +static FXD K1[4] = { + 0x00000000, + 0x00000000, + 0xFFFF3000, + 0xFFFF2400 +}; +FXD t1, t2, at1[256], at2[256]; +FXD t1_x, t2_x, at1_x[256], at2_x[256]; +#else +static double K0[4] = { + 0.0, + 0.9375, + 1.796875, + 1.53125 +}; +static double K1[4] = { + 0.0, + 0.0, + -0.8125, + -0.859375 +}; +double t1, t2, at1[256], at2[256]; +double t1_x, t2_x, at1_x[256], at2_x[256]; +#endif + +void initXaDecode(void) +{ + int i; + + for (i=0; i<256; ++i) + { + at1[i] = at2[i] = at1_x[i] = at2_x[i] = 0; + } +} +void reinitXaDecode(int i) +{ + at1[i] = at2[i] = at1_x[i] = at2_x[i] = 0; +} +void switchXaDecode(int i) +{ + t1 = at1[i]; + t2 = at2[i]; + t1_x = at1_x[i]; + t2_x = at2_x[i]; +} +void saveXaDecode(int i) +{ + at1[i] = t1; + at2[i] = t2; + at1_x[i]= t1_x; + at2_x[i]= t2_x; +} + +char xachannel(SoundSector *ss) +{ + return(ss->sectorFiller[XAChannel]); +} + +unsigned char xatype(SoundSector *ss) +{ + return(unsigned char) (ss->sectorFiller[XAType]); +} + +char xafileno(SoundSector *ss) +{ + return(ss->sectorFiller[XAFile]); +} + +char xastereo(SoundSector *ss) +{ + return(ss->sectorFiller[XAFlags]&XAFStereo); +} + +char xahalfhz(SoundSector *ss) +{ + return(ss->sectorFiller[XAFlags]&XAFHalfHz); +} + +long convXaToWave(char *adp, char *wav, int cn, int fn_s, int fn_e) +{ + SoundSector ssct; + int i; + + memcpy(ssct.sectorFiller,adp,sizeof(ssct.sectorFiller)); + for(i=0;i<18;i++) + memcpy(ssct.SoundGroups[i],adp+sizeof(ssct.sectorFiller)+(128*i),128); + if ((xachannel(&ssct) == cn) && (xatype(&ssct) == XAAUDIO)) + { + if (xafileno(&ssct) >= fn_s + && xafileno(&ssct) <= fn_e) + { + if (xastereo(&ssct)) + return(decodeSoundSect1(&ssct, wav)); + else + return(decodeSoundSect(&ssct, wav)); + } + } + return(0); +} + +long decodeSoundSect(SoundSector *ssct, char *wav) +{ + long count, outputBytes; + signed char snddat, filt, range; + short decoded; + long unit, sample; + long sndgrp; +#if USE_FXD + FXD tmp2, tmp3, tmp4, tmp5; +#else + double tmp2, tmp3, tmp4, tmp5; +#endif + + outputBytes = 0; + + for (sndgrp = 0; sndgrp < kNumOfSGs; sndgrp++) + { + count = 0; + for (unit = 0; unit < 8; unit++) + { + range = getRange(ssct->SoundGroups[sndgrp], unit); + filt = getFilter(ssct->SoundGroups[sndgrp], unit); + for (sample = 0; sample < 28; sample++) + { + snddat = getSoundData(ssct->SoundGroups[sndgrp], unit, sample); +#if USE_FXD + tmp2 = (long)(snddat) << (12 - range); + tmp3 = FXD_Pcm16ToFxd(tmp2); + tmp4 = FXD_FixMul(K0[filt], t1); + tmp5 = FXD_FixMul(K1[filt], t2); + t2 = t1; + t1 = tmp3 + tmp4 + tmp5; + decoded = FXD_FxdToPcm16(t1); +#else + tmp2 = (double)(1 << (12 - range)); + tmp3 = (double)snddat * tmp2; + tmp4 = t1 * K0[filt]; + tmp5 = t2 * K1[filt]; + t2 = t1; + t1 = tmp3 + tmp4 + tmp5; + decoded = DblToPCM(t1); +#endif + wav[outputBytes+count++] = (char)(decoded & 0x0000ffff); + wav[outputBytes+count++] = (char)(decoded >> 8); + } + } + outputBytes += count; + } + return outputBytes; +} + +long decodeSoundSect1(SoundSector *ssct, char *wav) +{ + long count, outputBytes; + signed char snddat, filt, range; + signed char filt1, range1; + short decoded; + long unit, sample; + long sndgrp; +#if USE_FXD + FXD tmp2, tmp3, tmp4, tmp5; +#else + double tmp2, tmp3, tmp4, tmp5; +#endif + + outputBytes = 0; + + for (sndgrp = 0; sndgrp < kNumOfSGs; sndgrp++) + { + count = 0; + for (unit = 0; unit < 8; unit+= 2) + { + range = getRange(ssct->SoundGroups[sndgrp], unit); + filt = getFilter(ssct->SoundGroups[sndgrp], unit); + range1 = getRange(ssct->SoundGroups[sndgrp], unit+1); + filt1 = getFilter(ssct->SoundGroups[sndgrp], unit+1); + + for (sample = 0; sample < 28; sample++) + { + /* Channel 1 */ + snddat = getSoundData(ssct->SoundGroups[sndgrp], unit, sample); +#if USE_FXD + tmp2 = (long)(snddat) << (12 - range); + tmp3 = FXD_Pcm16ToFxd(tmp2); + tmp4 = FXD_FixMul(K0[filt], t1); + tmp5 = FXD_FixMul(K1[filt], t2); + t2 = t1; + t1 = tmp3 + tmp4 + tmp5; + decoded = FXD_FxdToPcm16(t1); +#else + tmp2 = (double)(1 << (12 - range)); + tmp3 = (double)snddat * tmp2; + tmp4 = t1 * K0[filt]; + tmp5 = t2 * K1[filt]; + t2 = t1; + t1 = tmp3 + tmp4 + tmp5; + decoded = DblToPCM(t1); +#endif + wav[outputBytes + count++] = (char)(decoded & 0x0000ffff); + wav[outputBytes + count++] = (char)(decoded >> 8); + + /* Channel 2 */ + snddat = getSoundData(ssct->SoundGroups[sndgrp], unit+1, sample); +#if USE_FXD + tmp2 = (long)(snddat) << (12 - range1); + tmp3 = FXD_Pcm16ToFxd(tmp2); + tmp4 = FXD_FixMul(K0[filt1], t1_x); + tmp5 = FXD_FixMul(K1[filt1], t2_x); + t2_x = t1_x; + t1_x = tmp3 + tmp4 + tmp5; + decoded = FXD_FxdToPcm16(t1_x); +#else + tmp2 = (double)(1 << (12 - range1)); + tmp3 = (double)snddat * tmp2; + tmp4 = t1_x * K0[filt1]; + tmp5 = t2_x * K1[filt1]; + t2_x = t1_x; + t1_x = tmp3 + tmp4 + tmp5; + decoded = DblToPCM(t1_x); +#endif + wav[outputBytes + count++] = (char)(decoded & 0x0000ffff); + wav[outputBytes + count++] = (char)(decoded >> 8); + } + } + outputBytes += count; + } + return outputBytes; +} + +signed char getSoundData(char *buf, long unit, long sample) +{ + signed char ret; + char *p; + long offset, shift; + + p = buf; + shift = (unit%2) * 4; + + offset = 16 + (unit / 2) + (sample * 4); + p += offset; + + ret = (*p >> shift) & 0x0F; + + if (ret > 7) { + ret -= 16; + } + return ret; +} + +signed char getFilter(char *buf, long unit) +{ + return (*(buf + 4 + unit) >> 4) & 0x03; +} + + +signed char getRange(char *buf, long unit) +{ + return *(buf + 4 + unit) & 0x0F; +} + +#if USE_FXD +FXD FXD_FixMul(FXD a, FXD b) +{ + long high_a, low_a, high_b, low_b; + long hahb, halb, lahb; + unsigned long lalb; + FXD ret; + + high_a = a >> 16; + low_a = a & 0x0000FFFF; + high_b = b >> 16; + low_b = b & 0x0000FFFF; + + hahb = (high_a * high_b) << 16; + halb = high_a * low_b; + lahb = low_a * high_b; + lalb = (unsigned long)(low_a * low_b) >> 16; + + ret = hahb + halb + lahb + lalb; + + return ret; +} +#endif diff --git a/psxdev/xadecode.h b/psxdev/xadecode.h new file mode 100644 index 0000000..264012c --- /dev/null +++ b/psxdev/xadecode.h @@ -0,0 +1,82 @@ +/* + author: unknown, probably bitmaster? + slightly modified by dbalster +*/ + +#ifndef XADECODE_H +#define XADECODE_H + +#define USE_FXD 1 + +#define kNumOfSamples 224 +#define kNumOfSGs 18 + +#define XAFile 0 +#define XAChannel 1 +#define XAType 2 +#define XAFlags 3 +/* bits in XAFlags byte */ +#define XAFStereo 1<<0 +#define XAFHalfHz 1<<2 + +#define XAAUDIO 0x64 +#define XAVIDEO 0x48 +#define XABREAK 0xE4 +#define XACURRENT 0x100 /* for application use only! */ +#define XANONE 0x200 /* for application use only! */ +#define XAAV 0x400 /* for application use only! */ + +#define max(a,b) (ab?b:a) + +#define FXD_FxdToPCM(dt) (max(min((short)((dt)>>16), 32767), -32768)) +#define DblToPCM(dt) (short)(max(min((dt), 32767), -32768)) + +#define WHP_READ68_AUTO(fp, dt) WHP_Read68(dt, sizeof(*(dt)), 1, fp) +#define WHP_WRITE68_AUTO(fp, dt) WHP_Write68(dt, sizeof(*(dt)), 1, fp) + +#define WHP_CNV_SHORT68(dt, ndt) WHP_CnvEndianShort((dt), (ndt)) +#define WHP_CNV_LONG68(dt, ndt) WHP_CnvEndianLong((dt), (ndt)) + +#if USE_FXD +#define FXD_FxdToPcm16(dt) (max(min((dt)/2, 32767), -32768)) +#define FXD_Pcm16ToFxd(dt) ((long)dt*2) +#endif + +#define XAWAVBUFSIZE (kNumOfSamples*kNumOfSGs*2) + +typedef char SoundGroup[128]; + +typedef struct SoundSector { + char sectorFiller[8]; + SoundGroup SoundGroups[kNumOfSGs]; +} __attribute__((packed)) SoundSector; + +typedef unsigned long DWORD; +typedef unsigned short WORD; + +#if USE_FXD +typedef long FXD; +#endif + +long decodeSoundSect(SoundSector *ssct, char *wav); +long decodeSoundSect1(SoundSector *ssct, char *wav); +long convXaToWave(char *adp, char *wav, int cn, int fn_s, int fn_e); +void initXaDecode(void); +void switchXaDecode(int channel); +void saveXaDecode(int channel); +void reinitXaDecode(int channel); +signed char getSoundData(char *buf, long unit, long sample); +signed char getFilter(char *buf, long unit); +signed char getRange(char *buf, long unit); +char xachannel(SoundSector *ss); +unsigned char xatype(SoundSector *ss); +char xafileno(SoundSector *ss); +char xastereo(SoundSector *ss); +char xahalfhz(SoundSector *ss); + +#if USE_FXD +FXD FXD_FixMul(FXD a, FXD b); +#endif + +#endif diff --git a/str-util.cpp b/str-util.cpp index 3588707..67f20b1 100644 --- a/str-util.cpp +++ b/str-util.cpp @@ -1,6 +1,8 @@ #include #include -//#include "psxdev/bs.h" +#include +#include +#include "psxdev/bs.h" #include "fileutils.h" #include "generic.h" #include "cdutils.h" @@ -41,19 +43,26 @@ struct STR_Header { Byte * video = 0, * audio = 0; +int width, height; + +SDL_Surface * screen = 0; +Uint8 bpp; + +extern void mixaudio(void *unused, Uint8 *stream, int len); + void process_one_sector(FILE * f) { Byte sector[2336]; STR_Header * h; fread(sector, 2336, 1, f); h = (STR_Header *) ((Byte *) sector + 8); - + printm(M_BARE, "SubHeader FN : %x\n", sector[0]); printm(M_BARE, "SubHeader CN : %x\n", sector[1]); printm(M_BARE, "SubHeader SM : %x\n", sector[2]); printm(M_BARE, "SubHeader CI : %x\n", sector[3]); - - if (sector[2] == 0x48) { + + if ((sector[2] == 0x48) || (sector[2] == 0x42)) { printm(M_BARE, "Video sector\n"); printm(M_BARE, "Status : %04x\n", h->StSTATUS); printm(M_BARE, "Type : %04x\n", h->StTYPE); @@ -68,6 +77,17 @@ void process_one_sector(FILE * f) { printm(M_BARE, "Channels : %04x\n", h->Channels); if (h->StSECTOR_OFFSET == 0) { video = (Byte *) malloc(h->StSECTOR_SIZE * 2016); + if (!screen) { + bs_init(); + width = h->StMOVIE_WIDTH; + height = h->StMOVIE_HEIGHT; + screen = SDL_SetVideoMode(width, height, 24, SDL_HWSURFACE | SDL_DOUBLEBUF); + if (!screen) { + printm(M_ERROR, "Couldn't get framebuffer\n"); + exit(-1); + } + bpp = screen->format->BytesPerPixel; + } } memcpy(video + h->StSECTOR_OFFSET * 2016, sector + 40, 2016); @@ -76,19 +96,83 @@ void process_one_sector(FILE * f) { // Frame finished. printm(M_BARE, "End of Frame.\n"); + Uint8 * buffer = ((Uint8 *) screen->pixels); + + if (SDL_MUSTLOCK(screen)) + if (SDL_LockSurface(screen) < 0) + exit(1); + printm(M_BARE, "Width: %i, Height: %i - bpp: %i\n", width, height, bpp); + bs_decode_rgb24(buffer, (bs_header_t *) video, width, height, 0); + +// fwrite(screen->pixels, 3, width * height, stdout); + + if (SDL_MUSTLOCK(screen)) + SDL_UnlockSurface(screen); + SDL_Flip(screen); + free(video); } - } else if (sector[2] == 0x64) { + SoundSector * buffer = (SoundSector *) sector); printm(M_BARE, "Audio sector\n"); + printm(M_BARE, "Frequency: %i\n", xahalfhz(buffer) ? 18900 : 37800); + printm(M_BARE, "Channels : %s\n", xastereo(buffer) ? "stereo" : "mono"); +// fwrite(sector + 8, 1, 2324, stdout); + if (!audio) { + SDL_AudioSpec fmt; + + /* Un son sereo de 16 bits 44kHz */ + fmt.freq = xahalfhz(&buffer)?"18900":"37800"; + fmt.format = AUDIO_S16; + fmt.channels = 2; + fmt.samples = 512; /*Une bonne valeur pour les jeux */ + fmt.callback = mixaudio; + fmt.userdata = NULL; + + /* Ouvre le contexte audio et joue le son */ + if ( SDL_OpenAudio(&fmt, NULL) < 0 ) { + fprintf(stderr, "Impossible d'acce'der a` l'audio: %s\n", SDL_GetError()); + exit(1); + } + SDL_PauseAudio(0); + + } else { + free(audio); + } + audio = (Byte *) malloc(2336); } else { printm(M_BARE, "Unknow sector\n"); } printm(M_BARE, "---------------------------------\n\n"); } -int main(void) { +int main(int argc, char ** argv) { + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) < 0) { + printm(M_ERROR, "Couldn't initialise SDL: %s\n", SDL_GetError()); + exit(-1); + } + atexit(SDL_Quit); + SDL_ShowCursor(SDL_DISABLE); + + + switch (argc) { + case 1: + break; + case 2: + fclose(stdin); + stdin = fopen(argv[1], "r"); + break; + default: + printm(M_ERROR, "Too much arguments.\n"); + exit(-1); + } + while (!feof(stdin)) { process_one_sector(stdin); } + + if (!audio) + SDL_CloseAudio(); + + SDL_Quit(); } -- cgit v1.2.3