lotsa movie cleanups, added truecolor mve support, standalone mveplayer
This commit is contained in:
parent
5c138be691
commit
e1c12d4452
|
@ -1,10 +1,6 @@
|
|||
#ifndef INCLUDED_MVE_AUDIO_H
|
||||
#define INCLUDED_MVE_AUDIO_H
|
||||
|
||||
#define MVE_AUDIO_FLAGS_STEREO 1
|
||||
#define MVE_AUDIO_FLAGS_16BIT 2
|
||||
#define MVE_AUDIO_FLAGS_COMPRESSED 4
|
||||
|
||||
void mveaudio_uncompress(short *buffer, unsigned char *data, int length);
|
||||
|
||||
#endif /* INCLUDED_MVE_AUDIO_H */
|
||||
|
|
|
@ -19,12 +19,14 @@ typedef struct MVEFILE
|
|||
/*
|
||||
* open a .MVE file
|
||||
*/
|
||||
MVEFILE *mvefile_open(int filehandle);
|
||||
MVEFILE *mvefile_open(const char *filename);
|
||||
MVEFILE *mvefile_open_filehandle(int filehandle);
|
||||
|
||||
/*
|
||||
* close a .MVE file
|
||||
*/
|
||||
void mvefile_close(MVEFILE *movie);
|
||||
void mvefile_close_filehandle(MVEFILE *movie);
|
||||
|
||||
/*
|
||||
* get size of next segment in chunk (-1 if no more segments in chunk)
|
||||
|
@ -75,12 +77,14 @@ typedef struct MVESTREAM
|
|||
/*
|
||||
* open an MVE stream
|
||||
*/
|
||||
MVESTREAM *mve_open(int filehandle);
|
||||
MVESTREAM *mve_open(const char *filename);
|
||||
MVESTREAM *mve_open_filehandle(int filehandle);
|
||||
|
||||
/*
|
||||
* close an MVE stream
|
||||
*/
|
||||
void mve_close(MVESTREAM *movie);
|
||||
void mve_close_filehandle(MVESTREAM *movie);
|
||||
|
||||
/*
|
||||
* set segment type handler
|
||||
|
|
717
main/decoder16.c
Normal file
717
main/decoder16.c
Normal file
|
@ -0,0 +1,717 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
extern int g_width, g_height;
|
||||
extern void *g_vBackBuf1, *g_vBackBuf2;
|
||||
|
||||
/* 16 bit decoding routines */
|
||||
|
||||
static unsigned short *backBuf1, *backBuf2;
|
||||
static int lookup_initialized;
|
||||
|
||||
static void dispatchDecoder16(unsigned short **pFrame, unsigned char codeType, unsigned char **pData, unsigned char **pOffData, int *pDataRemain, int *curXb, int *curYb);
|
||||
static void genLoopkupTable();
|
||||
|
||||
void decodeFrame16(unsigned char *pFrame, unsigned char *pMap, int mapRemain, unsigned char *pData, int dataRemain)
|
||||
{
|
||||
unsigned char *pOrig;
|
||||
unsigned char *pOffData, *pEnd;
|
||||
unsigned short offset;
|
||||
int length;
|
||||
int op;
|
||||
int i, j;
|
||||
int xb, yb;
|
||||
|
||||
if (!lookup_initialized) {
|
||||
genLoopkupTable();
|
||||
}
|
||||
|
||||
backBuf1 = (unsigned short *)g_vBackBuf1;
|
||||
backBuf2 = (unsigned short *)g_vBackBuf2;
|
||||
|
||||
xb = g_width >> 3;
|
||||
yb = g_height >> 3;
|
||||
|
||||
offset = pData[0]|(pData[1]<<8);
|
||||
|
||||
pOffData = pData + offset;
|
||||
pEnd = pData + offset;
|
||||
|
||||
pData += 2;
|
||||
|
||||
pOrig = pData;
|
||||
length = offset - 2; /*dataRemain-2;*/
|
||||
|
||||
for (j=0; j<yb; j++)
|
||||
{
|
||||
for (i=0; i<xb/2; i++)
|
||||
{
|
||||
op = (*pMap) & 0xf;
|
||||
dispatchDecoder16((unsigned short **)&pFrame, op, &pData, &pOffData, &dataRemain, &i, &j);
|
||||
|
||||
/*
|
||||
if ((unsigned short *)pFrame < backBuf1)
|
||||
fprintf(stderr, "danger! pointing out of bounds below after dispatch decoder: %d, %d (1) [%x]\n", i, j, (*pMap) & 0xf);
|
||||
else if ((unsigned short *)pFrame >= backBuf1 + g_width*g_height)
|
||||
fprintf(stderr, "danger! pointing out of bounds above after dispatch decoder: %d, %d (1) [%x]\n", i, j, (*pMap) & 0xf);
|
||||
*/
|
||||
|
||||
op = ((*pMap) >> 4) & 0xf;
|
||||
dispatchDecoder16((unsigned short **)&pFrame, op, &pData, &pOffData, &dataRemain, &i, &j);
|
||||
|
||||
/*
|
||||
if ((unsigned short *)pFrame < backBuf1)
|
||||
fprintf(stderr, "danger! pointing out of bounds below after dispatch decoder: %d, %d (2) [%x]\n", i, j, (*pMap) >> 4);
|
||||
else if ((unsigned short *)pFrame >= backBuf1 + g_width*g_height)
|
||||
fprintf(stderr, "danger! pointing out of bounds above after dispatch decoder: %d, %d (2) [%x]\n", i, j, (*pMap) >> 4);
|
||||
*/
|
||||
|
||||
++pMap;
|
||||
--mapRemain;
|
||||
}
|
||||
|
||||
pFrame += 7*g_width*2;
|
||||
}
|
||||
|
||||
if ((length-(pData-pOrig)) != 0) {
|
||||
fprintf(stderr, "DEBUG: junk left over: %d,%d,%d\n", (pData-pOrig), length, (length-(pData-pOrig)));
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned short GETPIXEL(unsigned char **buf, int off)
|
||||
{
|
||||
unsigned short val = (*buf)[0+off] | ((*buf)[1+off] << 8);
|
||||
return val;
|
||||
}
|
||||
|
||||
static unsigned short GETPIXELI(unsigned char **buf, int off)
|
||||
{
|
||||
unsigned short val = (*buf)[0+off] | ((*buf)[1+off] << 8);
|
||||
(*buf) += 2;
|
||||
return val;
|
||||
}
|
||||
|
||||
static void relClose(int i, int *x, int *y)
|
||||
{
|
||||
int ma, mi;
|
||||
|
||||
ma = i >> 4;
|
||||
mi = i & 0xf;
|
||||
|
||||
*x = mi - 8;
|
||||
*y = ma - 8;
|
||||
}
|
||||
|
||||
static void relFar(int i, int sign, int *x, int *y)
|
||||
{
|
||||
if (i < 56)
|
||||
{
|
||||
*x = sign * (8 + (i % 7));
|
||||
*y = sign * (i / 7);
|
||||
}
|
||||
else
|
||||
{
|
||||
*x = sign * (-14 + (i - 56) % 29);
|
||||
*y = sign * (8 + (i - 56) / 29);
|
||||
}
|
||||
}
|
||||
|
||||
static int close_table[512];
|
||||
static int far_p_table[512];
|
||||
static int far_n_table[512];
|
||||
|
||||
static void genLoopkupTable()
|
||||
{
|
||||
int i;
|
||||
int x, y;
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
relClose(i, &x, &y);
|
||||
|
||||
close_table[i*2+0] = x;
|
||||
close_table[i*2+1] = y;
|
||||
|
||||
relFar(i, 1, &x, &y);
|
||||
|
||||
far_p_table[i*2+0] = x;
|
||||
far_p_table[i*2+1] = y;
|
||||
|
||||
relFar(i, -1, &x, &y);
|
||||
|
||||
far_n_table[i*2+0] = x;
|
||||
far_n_table[i*2+1] = y;
|
||||
}
|
||||
|
||||
lookup_initialized = 1;
|
||||
}
|
||||
|
||||
static void copyFrame(unsigned short *pDest, unsigned short *pSrc)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
memcpy(pDest, pSrc, 16);
|
||||
pDest += g_width;
|
||||
pSrc += g_width;
|
||||
}
|
||||
}
|
||||
|
||||
static void patternRow4Pixels(unsigned short *pFrame,
|
||||
unsigned char pat0, unsigned char pat1,
|
||||
unsigned short *p)
|
||||
{
|
||||
unsigned short mask=0x0003;
|
||||
unsigned short shift=0;
|
||||
unsigned short pattern = (pat1 << 8) | pat0;
|
||||
|
||||
while (mask != 0)
|
||||
{
|
||||
*pFrame++ = p[(mask & pattern) >> shift];
|
||||
mask <<= 2;
|
||||
shift += 2;
|
||||
}
|
||||
}
|
||||
|
||||
static void patternRow4Pixels2(unsigned short *pFrame,
|
||||
unsigned char pat0,
|
||||
unsigned short *p)
|
||||
{
|
||||
unsigned char mask=0x03;
|
||||
unsigned char shift=0;
|
||||
unsigned short pel;
|
||||
/* ORIGINAL VERSION IS BUGGY
|
||||
int skip=1;
|
||||
|
||||
while (mask != 0)
|
||||
{
|
||||
pel = p[(mask & pat0) >> shift];
|
||||
pFrame[0] = pel;
|
||||
pFrame[2] = pel;
|
||||
pFrame[g_width + 0] = pel;
|
||||
pFrame[g_width + 2] = pel;
|
||||
pFrame += skip;
|
||||
skip = 4 - skip;
|
||||
mask <<= 2;
|
||||
shift += 2;
|
||||
}
|
||||
*/
|
||||
while (mask != 0)
|
||||
{
|
||||
pel = p[(mask & pat0) >> shift];
|
||||
pFrame[0] = pel;
|
||||
pFrame[1] = pel;
|
||||
pFrame[g_width + 0] = pel;
|
||||
pFrame[g_width + 1] = pel;
|
||||
pFrame += 2;
|
||||
mask <<= 2;
|
||||
shift += 2;
|
||||
}
|
||||
}
|
||||
|
||||
static void patternRow4Pixels2x1(unsigned short *pFrame, unsigned char pat,
|
||||
unsigned short *p)
|
||||
{
|
||||
unsigned char mask=0x03;
|
||||
unsigned char shift=0;
|
||||
unsigned short pel;
|
||||
|
||||
while (mask != 0)
|
||||
{
|
||||
pel = p[(mask & pat) >> shift];
|
||||
pFrame[0] = pel;
|
||||
pFrame[1] = pel;
|
||||
pFrame += 2;
|
||||
mask <<= 2;
|
||||
shift += 2;
|
||||
}
|
||||
}
|
||||
|
||||
static void patternQuadrant4Pixels(unsigned short *pFrame,
|
||||
unsigned char pat0, unsigned char pat1, unsigned char pat2,
|
||||
unsigned char pat3, unsigned short *p)
|
||||
{
|
||||
unsigned long mask = 0x00000003UL;
|
||||
int shift=0;
|
||||
int i;
|
||||
unsigned long pat = (pat3 << 24) | (pat2 << 16) | (pat1 << 8) | pat0;
|
||||
|
||||
for (i=0; i<16; i++)
|
||||
{
|
||||
pFrame[i&3] = p[(pat & mask) >> shift];
|
||||
|
||||
if ((i&3) == 3)
|
||||
pFrame += g_width;
|
||||
|
||||
mask <<= 2;
|
||||
shift += 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void patternRow2Pixels(unsigned short *pFrame, unsigned char pat,
|
||||
unsigned short *p)
|
||||
{
|
||||
unsigned char mask=0x01;
|
||||
|
||||
while (mask != 0)
|
||||
{
|
||||
*pFrame++ = p[(mask & pat) ? 1 : 0];
|
||||
mask <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void patternRow2Pixels2(unsigned short *pFrame, unsigned char pat,
|
||||
unsigned short *p)
|
||||
{
|
||||
unsigned short pel;
|
||||
unsigned char mask=0x1;
|
||||
|
||||
/* ORIGINAL VERSION IS BUGGY
|
||||
int skip=1;
|
||||
while (mask != 0x10)
|
||||
{
|
||||
pel = p[(mask & pat) ? 1 : 0];
|
||||
pFrame[0] = pel;
|
||||
pFrame[2] = pel;
|
||||
pFrame[g_width + 0] = pel;
|
||||
pFrame[g_width + 2] = pel;
|
||||
pFrame += skip;
|
||||
skip = 4 - skip;
|
||||
mask <<= 1;
|
||||
}
|
||||
*/
|
||||
while (mask != 0x10) {
|
||||
pel = p[(mask & pat) ? 1 : 0];
|
||||
|
||||
pFrame[0] = pel;
|
||||
pFrame[1] = pel;
|
||||
pFrame[g_width + 0] = pel;
|
||||
pFrame[g_width + 1] = pel;
|
||||
pFrame += 2;
|
||||
|
||||
mask <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void patternQuadrant2Pixels(unsigned short *pFrame, unsigned char pat0,
|
||||
unsigned char pat1, unsigned short *p)
|
||||
{
|
||||
unsigned short mask = 0x0001;
|
||||
int i;
|
||||
unsigned short pat = (pat1 << 8) | pat0;
|
||||
|
||||
for (i=0; i<16; i++)
|
||||
{
|
||||
pFrame[i&3] = p[(pat & mask) ? 1 : 0];
|
||||
|
||||
if ((i&3) == 3)
|
||||
pFrame += g_width;
|
||||
|
||||
mask <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void dispatchDecoder16(unsigned short **pFrame, unsigned char codeType, unsigned char **pData, unsigned char **pOffData, int *pDataRemain, int *curXb, int *curYb)
|
||||
{
|
||||
unsigned short p[4];
|
||||
unsigned char pat[16];
|
||||
int i, j, k;
|
||||
int x, y;
|
||||
unsigned short *pDstBak;
|
||||
|
||||
pDstBak = *pFrame;
|
||||
|
||||
switch(codeType)
|
||||
{
|
||||
case 0x0:
|
||||
copyFrame(*pFrame, *pFrame + (backBuf2 - backBuf1));
|
||||
case 0x1:
|
||||
break;
|
||||
case 0x2: /*
|
||||
relFar(*(*pOffData)++, 1, &x, &y);
|
||||
*/
|
||||
|
||||
k = *(*pOffData)++;
|
||||
x = far_p_table[k*2+0];
|
||||
y = far_p_table[k*2+1];
|
||||
|
||||
copyFrame(*pFrame, *pFrame + x + y*g_width);
|
||||
--*pDataRemain;
|
||||
break;
|
||||
case 0x3: /*
|
||||
relFar(*(*pOffData)++, -1, &x, &y);
|
||||
*/
|
||||
|
||||
k = *(*pOffData)++;
|
||||
x = far_n_table[k*2+0];
|
||||
y = far_n_table[k*2+1];
|
||||
|
||||
copyFrame(*pFrame, *pFrame + x + y*g_width);
|
||||
--*pDataRemain;
|
||||
break;
|
||||
case 0x4: /*
|
||||
relClose(*(*pOffData)++, &x, &y);
|
||||
*/
|
||||
|
||||
k = *(*pOffData)++;
|
||||
x = close_table[k*2+0];
|
||||
y = close_table[k*2+1];
|
||||
|
||||
copyFrame(*pFrame, *pFrame + (backBuf2 - backBuf1) + x + y*g_width);
|
||||
--*pDataRemain;
|
||||
break;
|
||||
case 0x5:
|
||||
x = (char)*(*pData)++;
|
||||
y = (char)*(*pData)++;
|
||||
copyFrame(*pFrame, *pFrame + (backBuf2 - backBuf1) + x + y*g_width);
|
||||
*pDataRemain -= 2;
|
||||
break;
|
||||
case 0x6:
|
||||
fprintf(stderr, "STUB: encoding 6 not tested\n");
|
||||
for (i=0; i<2; i++)
|
||||
{
|
||||
*pFrame += 16;
|
||||
if (++*curXb == (g_width >> 3))
|
||||
{
|
||||
*pFrame += 7*g_width;
|
||||
*curXb = 0;
|
||||
if (++*curYb == (g_height >> 3))
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x7:
|
||||
p[0] = GETPIXELI(pData, 0);
|
||||
p[1] = GETPIXELI(pData, 0);
|
||||
|
||||
if (!((p[0]/*|p[1]*/)&0x8000))
|
||||
{
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
patternRow2Pixels(*pFrame, *(*pData), p);
|
||||
(*pData)++;
|
||||
|
||||
*pFrame += g_width;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i=0; i<2; i++)
|
||||
{
|
||||
patternRow2Pixels2(*pFrame, *(*pData) & 0xf, p);
|
||||
*pFrame += 2*g_width;
|
||||
patternRow2Pixels2(*pFrame, *(*pData) >> 4, p);
|
||||
(*pData)++;
|
||||
|
||||
*pFrame += 2*g_width;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8:
|
||||
p[0] = GETPIXEL(pData, 0);
|
||||
|
||||
if (!(p[0] & 0x8000))
|
||||
{
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
p[0] = GETPIXELI(pData, 0);
|
||||
p[1] = GETPIXELI(pData, 0);
|
||||
|
||||
pat[0] = (*pData)[0];
|
||||
pat[1] = (*pData)[1];
|
||||
(*pData) += 2;
|
||||
|
||||
patternQuadrant2Pixels(*pFrame, pat[0], pat[1], p);
|
||||
|
||||
if (i & 1)
|
||||
*pFrame -= (4*g_width - 4);
|
||||
else
|
||||
*pFrame += 4*g_width;
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
p[2] = GETPIXEL(pData, 8);
|
||||
|
||||
if (!(p[2]&0x8000)) {
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
if ((i & 1) == 0)
|
||||
{
|
||||
p[0] = GETPIXELI(pData, 0);
|
||||
p[1] = GETPIXELI(pData, 0);
|
||||
}
|
||||
pat[0] = *(*pData)++;
|
||||
pat[1] = *(*pData)++;
|
||||
patternQuadrant2Pixels(*pFrame, pat[0], pat[1], p);
|
||||
|
||||
if (i & 1)
|
||||
*pFrame -= (4*g_width - 4);
|
||||
else
|
||||
*pFrame += 4*g_width;
|
||||
}
|
||||
} else {
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
if ((i & 3) == 0)
|
||||
{
|
||||
p[0] = GETPIXELI(pData, 0);
|
||||
p[1] = GETPIXELI(pData, 0);
|
||||
}
|
||||
patternRow2Pixels(*pFrame, *(*pData), p);
|
||||
(*pData)++;
|
||||
|
||||
*pFrame += g_width;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x9:
|
||||
p[0] = GETPIXELI(pData, 0);
|
||||
p[1] = GETPIXELI(pData, 0);
|
||||
p[2] = GETPIXELI(pData, 0);
|
||||
p[3] = GETPIXELI(pData, 0);
|
||||
|
||||
*pDataRemain -= 8;
|
||||
|
||||
if (!(p[0] & 0x8000))
|
||||
{
|
||||
if (!(p[2] & 0x8000))
|
||||
{
|
||||
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
pat[0] = (*pData)[0];
|
||||
pat[1] = (*pData)[1];
|
||||
(*pData) += 2;
|
||||
patternRow4Pixels(*pFrame, pat[0], pat[1], p);
|
||||
*pFrame += g_width;
|
||||
}
|
||||
*pDataRemain -= 16;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
patternRow4Pixels2(*pFrame, (*pData)[0], p);
|
||||
*pFrame += 2*g_width;
|
||||
patternRow4Pixels2(*pFrame, (*pData)[1], p);
|
||||
*pFrame += 2*g_width;
|
||||
patternRow4Pixels2(*pFrame, (*pData)[2], p);
|
||||
*pFrame += 2*g_width;
|
||||
patternRow4Pixels2(*pFrame, (*pData)[3], p);
|
||||
|
||||
(*pData) += 4;
|
||||
*pDataRemain -= 4;
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(p[2] & 0x8000))
|
||||
{
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
pat[0] = (*pData)[0];
|
||||
(*pData) += 1;
|
||||
patternRow4Pixels2x1(*pFrame, pat[0], p);
|
||||
*pFrame += g_width;
|
||||
}
|
||||
*pDataRemain -= 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
pat[0] = (*pData)[0];
|
||||
pat[1] = (*pData)[1];
|
||||
|
||||
(*pData) += 2;
|
||||
|
||||
patternRow4Pixels(*pFrame, pat[0], pat[1], p);
|
||||
*pFrame += g_width;
|
||||
patternRow4Pixels(*pFrame, pat[0], pat[1], p);
|
||||
*pFrame += g_width;
|
||||
}
|
||||
*pDataRemain -= 8;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xa:
|
||||
p[0] = GETPIXEL(pData, 0);
|
||||
|
||||
if (!(p[0] & 0x8000))
|
||||
{
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
p[0] = GETPIXELI(pData, 0);
|
||||
p[1] = GETPIXELI(pData, 0);
|
||||
p[2] = GETPIXELI(pData, 0);
|
||||
p[3] = GETPIXELI(pData, 0);
|
||||
pat[0] = (*pData)[0];
|
||||
pat[1] = (*pData)[1];
|
||||
pat[2] = (*pData)[2];
|
||||
pat[3] = (*pData)[3];
|
||||
|
||||
(*pData) += 4;
|
||||
|
||||
patternQuadrant4Pixels(*pFrame, pat[0], pat[1], pat[2], pat[3], p);
|
||||
|
||||
if (i & 1)
|
||||
*pFrame -= (4*g_width - 4);
|
||||
else
|
||||
*pFrame += 4*g_width;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
p[0] = GETPIXEL(pData, 16);
|
||||
|
||||
if (!(p[0] & 0x8000))
|
||||
{
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
if ((i&1) == 0)
|
||||
{
|
||||
p[0] = GETPIXELI(pData, 0);
|
||||
p[1] = GETPIXELI(pData, 0);
|
||||
p[2] = GETPIXELI(pData, 0);
|
||||
p[3] = GETPIXELI(pData, 0);
|
||||
}
|
||||
|
||||
pat[0] = (*pData)[0];
|
||||
pat[1] = (*pData)[1];
|
||||
pat[2] = (*pData)[2];
|
||||
pat[3] = (*pData)[3];
|
||||
|
||||
(*pData) += 4;
|
||||
|
||||
patternQuadrant4Pixels(*pFrame, pat[0], pat[1], pat[2], pat[3], p);
|
||||
|
||||
if (i & 1)
|
||||
*pFrame -= (4*g_width - 4);
|
||||
else
|
||||
*pFrame += 4*g_width;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
if ((i&3) == 0)
|
||||
{
|
||||
p[0] = GETPIXELI(pData, 0);
|
||||
p[1] = GETPIXELI(pData, 0);
|
||||
p[2] = GETPIXELI(pData, 0);
|
||||
p[3] = GETPIXELI(pData, 0);
|
||||
}
|
||||
|
||||
pat[0] = (*pData)[0];
|
||||
pat[1] = (*pData)[1];
|
||||
patternRow4Pixels(*pFrame, pat[0], pat[1], p);
|
||||
*pFrame += g_width;
|
||||
|
||||
(*pData) += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xb:
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
memcpy(*pFrame, *pData, 16);
|
||||
*pFrame += g_width;
|
||||
*pData += 16;
|
||||
*pDataRemain -= 16;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xc:
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
p[0] = GETPIXEL(pData, 0);
|
||||
p[1] = GETPIXEL(pData, 2);
|
||||
p[2] = GETPIXEL(pData, 4);
|
||||
p[3] = GETPIXEL(pData, 6);
|
||||
|
||||
for (j=0; j<2; j++)
|
||||
{
|
||||
for (k=0; k<4; k++)
|
||||
{
|
||||
(*pFrame)[j+2*k] = p[k];
|
||||
(*pFrame)[g_width+j+2*k] = p[k];
|
||||
}
|
||||
*pFrame += g_width;
|
||||
}
|
||||
*pData += 8;
|
||||
*pDataRemain -= 8;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xd:
|
||||
for (i=0; i<2; i++)
|
||||
{
|
||||
p[0] = GETPIXEL(pData, 0);
|
||||
p[1] = GETPIXEL(pData, 2);
|
||||
|
||||
for (j=0; j<4; j++)
|
||||
{
|
||||
for (k=0; k<4; k++)
|
||||
{
|
||||
(*pFrame)[k*g_width+j] = p[0];
|
||||
(*pFrame)[k*g_width+j+4] = p[1];
|
||||
}
|
||||
}
|
||||
|
||||
*pFrame += 4*g_width;
|
||||
|
||||
*pData += 4;
|
||||
*pDataRemain -= 4;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xe:
|
||||
p[0] = GETPIXEL(pData, 0);
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
for (j = 0; j < 8; j++) {
|
||||
(*pFrame)[j] = p[0];
|
||||
}
|
||||
|
||||
*pFrame += g_width;
|
||||
}
|
||||
|
||||
*pData += 2;
|
||||
*pDataRemain -= 2;
|
||||
|
||||
break;
|
||||
|
||||
case 0xf:
|
||||
p[0] = GETPIXEL(pData, 0);
|
||||
p[1] = GETPIXEL(pData, 1);
|
||||
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
for (j=0; j<8; j++)
|
||||
{
|
||||
(*pFrame)[j] = p[(i+j)&1];
|
||||
}
|
||||
*pFrame += g_width;
|
||||
}
|
||||
|
||||
*pData += 4;
|
||||
*pDataRemain -= 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
*pFrame = pDstBak+8;
|
||||
}
|
872
main/decoder8.c
Normal file
872
main/decoder8.c
Normal file
|
@ -0,0 +1,872 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
extern int g_width, g_height;
|
||||
extern void *g_vBackBuf1, *g_vBackBuf2;
|
||||
|
||||
/* 8 bit decoding routines */
|
||||
|
||||
static void dispatchDecoder(unsigned char **pFrame, unsigned char codeType, unsigned char **pData, int *pDataRemain, int *curXb, int *curYb);
|
||||
|
||||
void decodeFrame8(unsigned char *pFrame, unsigned char *pMap, int mapRemain, unsigned char *pData, int dataRemain)
|
||||
{
|
||||
int i, j;
|
||||
int xb, yb;
|
||||
|
||||
xb = g_width >> 3;
|
||||
yb = g_height >> 3;
|
||||
for (j=0; j<yb; j++)
|
||||
{
|
||||
for (i=0; i<xb/2; i++)
|
||||
{
|
||||
dispatchDecoder(&pFrame, (*pMap) & 0xf, &pData, &dataRemain, &i, &j);
|
||||
if (pFrame < (unsigned char *)g_vBackBuf1)
|
||||
fprintf(stderr, "danger! pointing out of bounds below after dispatch decoder: %d, %d (1) [%x]\n", i, j, (*pMap) & 0xf);
|
||||
else if (pFrame >= ((unsigned char *)g_vBackBuf1) + g_width*g_height)
|
||||
fprintf(stderr, "danger! pointing out of bounds above after dispatch decoder: %d, %d (1) [%x]\n", i, j, (*pMap) & 0xf);
|
||||
dispatchDecoder(&pFrame, (*pMap) >> 4, &pData, &dataRemain, &i, &j);
|
||||
if (pFrame < (unsigned char *)g_vBackBuf1)
|
||||
fprintf(stderr, "danger! pointing out of bounds below after dispatch decoder: %d, %d (2) [%x]\n", i, j, (*pMap) >> 4);
|
||||
else if (pFrame >= ((unsigned char *)g_vBackBuf1) + g_width*g_height)
|
||||
fprintf(stderr, "danger! pointing out of bounds above after dispatch decoder: %d, %d (2) [%x]\n", i, j, (*pMap) >> 4);
|
||||
|
||||
++pMap;
|
||||
--mapRemain;
|
||||
}
|
||||
|
||||
pFrame += 7*g_width;
|
||||
}
|
||||
}
|
||||
|
||||
static void relClose(int i, int *x, int *y)
|
||||
{
|
||||
int ma, mi;
|
||||
|
||||
ma = i >> 4;
|
||||
mi = i & 0xf;
|
||||
|
||||
*x = mi - 8;
|
||||
*y = ma - 8;
|
||||
}
|
||||
|
||||
static void relFar(int i, int sign, int *x, int *y)
|
||||
{
|
||||
if (i < 56)
|
||||
{
|
||||
*x = sign * (8 + (i % 7));
|
||||
*y = sign * (i / 7);
|
||||
}
|
||||
else
|
||||
{
|
||||
*x = sign * (-14 + (i - 56) % 29);
|
||||
*y = sign * (8 + (i - 56) / 29);
|
||||
}
|
||||
}
|
||||
|
||||
/* copies an 8x8 block from pSrc to pDest.
|
||||
pDest and pSrc are both g_width bytes wide */
|
||||
static void copyFrame(unsigned char *pDest, unsigned char *pSrc)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
memcpy(pDest, pSrc, 8);
|
||||
pDest += g_width;
|
||||
pSrc += g_width;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill in the next eight bytes with p[0], p[1], p[2], or p[3],
|
||||
// depending on the corresponding two-bit value in pat0 and pat1
|
||||
static void patternRow4Pixels(unsigned char *pFrame,
|
||||
unsigned char pat0, unsigned char pat1,
|
||||
unsigned char *p)
|
||||
{
|
||||
unsigned short mask=0x0003;
|
||||
unsigned short shift=0;
|
||||
unsigned short pattern = (pat1 << 8) | pat0;
|
||||
|
||||
while (mask != 0)
|
||||
{
|
||||
*pFrame++ = p[(mask & pattern) >> shift];
|
||||
mask <<= 2;
|
||||
shift += 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill in the next four 2x2 pixel blocks with p[0], p[1], p[2], or p[3],
|
||||
// depending on the corresponding two-bit value in pat0.
|
||||
static void patternRow4Pixels2(unsigned char *pFrame,
|
||||
unsigned char pat0,
|
||||
unsigned char *p)
|
||||
{
|
||||
unsigned char mask=0x03;
|
||||
unsigned char shift=0;
|
||||
unsigned char pel;
|
||||
|
||||
while (mask != 0)
|
||||
{
|
||||
pel = p[(mask & pat0) >> shift];
|
||||
pFrame[0] = pel;
|
||||
pFrame[1] = pel;
|
||||
pFrame[g_width + 0] = pel;
|
||||
pFrame[g_width + 1] = pel;
|
||||
pFrame += 2;
|
||||
mask <<= 2;
|
||||
shift += 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill in the next four 2x1 pixel blocks with p[0], p[1], p[2], or p[3],
|
||||
// depending on the corresponding two-bit value in pat.
|
||||
static void patternRow4Pixels2x1(unsigned char *pFrame, unsigned char pat, unsigned char *p)
|
||||
{
|
||||
unsigned char mask=0x03;
|
||||
unsigned char shift=0;
|
||||
unsigned char pel;
|
||||
|
||||
while (mask != 0)
|
||||
{
|
||||
pel = p[(mask & pat) >> shift];
|
||||
pFrame[0] = pel;
|
||||
pFrame[1] = pel;
|
||||
pFrame += 2;
|
||||
mask <<= 2;
|
||||
shift += 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill in the next 4x4 pixel block with p[0], p[1], p[2], or p[3],
|
||||
// depending on the corresponding two-bit value in pat0, pat1, pat2, and pat3.
|
||||
static void patternQuadrant4Pixels(unsigned char *pFrame, unsigned char pat0, unsigned char pat1, unsigned char pat2, unsigned char pat3, unsigned char *p)
|
||||
{
|
||||
unsigned long mask = 0x00000003UL;
|
||||
int shift=0;
|
||||
int i;
|
||||
unsigned long pat = (pat3 << 24) | (pat2 << 16) | (pat1 << 8) | pat0;
|
||||
|
||||
for (i=0; i<16; i++)
|
||||
{
|
||||
pFrame[i&3] = p[(pat & mask) >> shift];
|
||||
|
||||
if ((i&3) == 3)
|
||||
pFrame += g_width;
|
||||
|
||||
mask <<= 2;
|
||||
shift += 2;
|
||||
}
|
||||
}
|
||||
|
||||
// fills the next 8 pixels with either p[0] or p[1], depending on pattern
|
||||
static void patternRow2Pixels(unsigned char *pFrame, unsigned char pat, unsigned char *p)
|
||||
{
|
||||
unsigned char mask=0x01;
|
||||
|
||||
while (mask != 0)
|
||||
{
|
||||
*pFrame++ = p[(mask & pat) ? 1 : 0];
|
||||
mask <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// fills the next four 2 x 2 pixel boxes with either p[0] or p[1], depending on pattern
|
||||
static void patternRow2Pixels2(unsigned char *pFrame, unsigned char pat, unsigned char *p)
|
||||
{
|
||||
unsigned char pel;
|
||||
unsigned char mask=0x1;
|
||||
|
||||
while (mask != 0x10)
|
||||
{
|
||||
pel = p[(mask & pat) ? 1 : 0];
|
||||
|
||||
pFrame[0] = pel; // upper-left
|
||||
pFrame[1] = pel; // upper-right
|
||||
pFrame[g_width + 0] = pel; // lower-left
|
||||
pFrame[g_width + 1] = pel; // lower-right
|
||||
pFrame += 2;
|
||||
|
||||
mask <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// fills pixels in the next 4 x 4 pixel boxes with either p[0] or p[1], depending on pat0 and pat1.
|
||||
static void patternQuadrant2Pixels(unsigned char *pFrame, unsigned char pat0, unsigned char pat1, unsigned char *p)
|
||||
{
|
||||
unsigned char pel;
|
||||
unsigned short mask = 0x0001;
|
||||
int i, j;
|
||||
unsigned short pat = (pat1 << 8) | pat0;
|
||||
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
for (j=0; j<4; j++)
|
||||
{
|
||||
pel = p[(pat & mask) ? 1 : 0];
|
||||
|
||||
pFrame[j + i * g_width] = pel;
|
||||
|
||||
mask <<= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void dispatchDecoder(unsigned char **pFrame, unsigned char codeType, unsigned char **pData, int *pDataRemain, int *curXb, int *curYb)
|
||||
{
|
||||
unsigned char p[4];
|
||||
unsigned char pat[16];
|
||||
int i, j, k;
|
||||
int x, y;
|
||||
|
||||
/* Data is processed in 8x8 pixel blocks.
|
||||
There are 16 ways to encode each block.
|
||||
*/
|
||||
|
||||
switch(codeType)
|
||||
{
|
||||
case 0x0:
|
||||
/* block is copied from block in current frame */
|
||||
copyFrame(*pFrame, *pFrame + (g_vBackBuf2 - g_vBackBuf1));
|
||||
case 0x1:
|
||||
/* block is unchanged from two frames ago */
|
||||
*pFrame += 8;
|
||||
break;
|
||||
|
||||
case 0x2:
|
||||
/* Block is copied from nearby (below and/or to the right) within the
|
||||
new frame. The offset within the buffer from which to grab the
|
||||
patch of 8 pixels is given by grabbing a byte B from the data
|
||||
stream, which is broken into a positive x and y offset according
|
||||
to the following mapping:
|
||||
|
||||
if B < 56:
|
||||
x = 8 + (B % 7)
|
||||
y = B / 7
|
||||
else
|
||||
x = -14 + ((B - 56) % 29)
|
||||
y = 8 + ((B - 56) / 29)
|
||||
*/
|
||||
relFar(*(*pData)++, 1, &x, &y);
|
||||
copyFrame(*pFrame, *pFrame + x + y*g_width);
|
||||
*pFrame += 8;
|
||||
--*pDataRemain;
|
||||
break;
|
||||
|
||||
case 0x3:
|
||||
/* Block is copied from nearby (above and/or to the left) within the
|
||||
new frame.
|
||||
|
||||
if B < 56:
|
||||
x = -(8 + (B % 7))
|
||||
y = -(B / 7)
|
||||
else
|
||||
x = -(-14 + ((B - 56) % 29))
|
||||
y = -( 8 + ((B - 56) / 29))
|
||||
*/
|
||||
relFar(*(*pData)++, -1, &x, &y);
|
||||
copyFrame(*pFrame, *pFrame + x + y*g_width);
|
||||
*pFrame += 8;
|
||||
--*pDataRemain;
|
||||
break;
|
||||
|
||||
case 0x4:
|
||||
/* Similar to 0x2 and 0x3, except this method copies from the
|
||||
"current" frame, rather than the "new" frame, and instead of the
|
||||
lopsided mapping they use, this one uses one which is symmetric
|
||||
and centered around the top-left corner of the block. This uses
|
||||
only 1 byte still, though, so the range is decreased, since we
|
||||
have to encode all directions in a single byte. The byte we pull
|
||||
from the data stream, I'll call B. Call the highest 4 bits of B
|
||||
BH and the lowest 4 bytes BL. Then the offset from which to copy
|
||||
the data is:
|
||||
|
||||
x = -8 + BL
|
||||
y = -8 + BH
|
||||
*/
|
||||
relClose(*(*pData)++, &x, &y);
|
||||
copyFrame(*pFrame, *pFrame + (g_vBackBuf2 - g_vBackBuf1) + x + y*g_width);
|
||||
*pFrame += 8;
|
||||
--*pDataRemain;
|
||||
break;
|
||||
|
||||
case 0x5:
|
||||
/* Similar to 0x4, but instead of one byte for the offset, this uses
|
||||
two bytes to encode a larger range, the first being the x offset
|
||||
as a signed 8-bit value, and the second being the y offset as a
|
||||
signed 8-bit value.
|
||||
*/
|
||||
x = (signed char)*(*pData)++;
|
||||
y = (signed char)*(*pData)++;
|
||||
copyFrame(*pFrame, *pFrame + (g_vBackBuf2 - g_vBackBuf1) + x + y*g_width);
|
||||
*pFrame += 8;
|
||||
*pDataRemain -= 2;
|
||||
break;
|
||||
|
||||
case 0x6:
|
||||
/* I can't figure out how any file containing a block of this type
|
||||
could still be playable, since it appears that it would leave the
|
||||
internal bookkeeping in an inconsistent state in the BG player
|
||||
code. Ahh, well. Perhaps it was a bug in the BG player code that
|
||||
just didn't happen to be exposed by any of the included movies.
|
||||
Anyway, this skips the next two blocks, doing nothing to them.
|
||||
Note that if you've reached the end of a row, this means going on
|
||||
to the next row.
|
||||
*/
|
||||
for (i=0; i<2; i++)
|
||||
{
|
||||
*pFrame += 16;
|
||||
if (++*curXb == (g_width >> 3))
|
||||
{
|
||||
*pFrame += 7*g_width;
|
||||
*curXb = 0;
|
||||
if (++*curYb == (g_height >> 3))
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x7:
|
||||
/* Ok, here's where it starts to get really...interesting. This is,
|
||||
incidentally, the part where they started using self-modifying
|
||||
code. So, most of the following encodings are "patterned" blocks,
|
||||
where we are given a number of pixel values and then bitmapped
|
||||
values to specify which pixel values belong to which squares. For
|
||||
this encoding, we are given the following in the data stream:
|
||||
|
||||
P0 P1
|
||||
|
||||
These are pixel values (i.e. 8-bit indices into the palette). If
|
||||
P0 <= P1, we then get 8 more bytes from the data stream, one for
|
||||
each row in the block:
|
||||
|
||||
B0 B1 B2 B3 B4 B5 B6 B7
|
||||
|
||||
For each row, the leftmost pixel is represented by the low-order
|
||||
bit, and the rightmost by the high-order bit. Use your imagination
|
||||
in between. If a bit is set, the pixel value is P1 and if it is
|
||||
unset, the pixel value is P0.
|
||||
|
||||
So, for example, if we had:
|
||||
|
||||
11 22 fe 83 83 83 83 83 83 fe
|
||||
|
||||
This would represent the following layout:
|
||||
|
||||
11 22 22 22 22 22 22 22 ; fe == 11111110
|
||||
22 22 11 11 11 11 11 22 ; 83 == 10000011
|
||||
22 22 11 11 11 11 11 22 ; 83 == 10000011
|
||||
22 22 11 11 11 11 11 22 ; 83 == 10000011
|
||||
22 22 11 11 11 11 11 22 ; 83 == 10000011
|
||||
22 22 11 11 11 11 11 22 ; 83 == 10000011
|
||||
22 22 11 11 11 11 11 22 ; 83 == 10000011
|
||||
11 22 22 22 22 22 22 22 ; fe == 11111110
|
||||
|
||||
If, on the other hand, P0 > P1, we get two more bytes from the
|
||||
data stream:
|
||||
|
||||
B0 B1
|
||||
|
||||
Each of these bytes contains two 4-bit patterns. These patterns
|
||||
work like the patterns above with 8 bytes, except each bit
|
||||
represents a 2x2 pixel region.
|
||||
|
||||
B0 contains the pattern for the top two rows and B1 contains
|
||||
the pattern for the bottom two rows. Note that the low-order
|
||||
nibble of each byte contains the pattern for the upper of the
|
||||
two rows that that byte controls.
|
||||
|
||||
So if we had:
|
||||
|
||||
22 11 7e 83
|
||||
|
||||
The output would be:
|
||||
|
||||
11 11 22 22 22 22 22 22 ; e == 1 1 1 0
|
||||
11 11 22 22 22 22 22 22 ;
|
||||
22 22 22 22 22 22 11 11 ; 7 == 0 1 1 1
|
||||
22 22 22 22 22 22 11 11 ;
|
||||
11 11 11 11 11 11 22 22 ; 3 == 1 0 0 0
|
||||
11 11 11 11 11 11 22 22 ;
|
||||
22 22 22 22 11 11 11 11 ; 8 == 0 0 1 1
|
||||
22 22 22 22 11 11 11 11 ;
|
||||
*/
|
||||
p[0] = *(*pData)++;
|
||||
p[1] = *(*pData)++;
|
||||
if (p[0] <= p[1])
|
||||
{
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
patternRow2Pixels(*pFrame, *(*pData)++, p);
|
||||
*pFrame += g_width;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i=0; i<2; i++)
|
||||
{
|
||||
patternRow2Pixels2(*pFrame, *(*pData) & 0xf, p);
|
||||
*pFrame += 2*g_width;
|
||||
patternRow2Pixels2(*pFrame, *(*pData)++ >> 4, p);
|
||||
*pFrame += 2*g_width;
|
||||
}
|
||||
}
|
||||
*pFrame -= (8*g_width - 8);
|
||||
break;
|
||||
|
||||
case 0x8:
|
||||
/* Ok, this one is basically like encoding 0x7, only more
|
||||
complicated. Again, we start out by getting two bytes on the data
|
||||
stream:
|
||||
|
||||
P0 P1
|
||||
|
||||
if P0 <= P1 then we get the following from the data stream:
|
||||
|
||||
B0 B1
|
||||
P2 P3 B2 B3
|
||||
P4 P5 B4 B5
|
||||
P6 P7 B6 B7
|
||||
|
||||
P0 P1 and B0 B1 are used for the top-left corner, P2 P3 B2 B3 for
|
||||
the bottom-left corner, P4 P5 B4 B5 for the top-right, P6 P7 B6 B7
|
||||
for the bottom-right. (So, each codes for a 4x4 pixel array.)
|
||||
Since we have 16 bits in B0 B1, there is one bit for each pixel in
|
||||
the array. The convention for the bit-mapping is, again, left to
|
||||
right and top to bottom.
|
||||
|
||||
So, basically, the top-left quarter of the block is an arbitrary
|
||||
pattern with 2 pixels, the bottom-left a different arbitrary
|
||||
pattern with 2 different pixels, and so on.
|
||||
|
||||
For example if the next 16 bytes were:
|
||||
|
||||
00 22 f9 9f 44 55 aa 55 11 33 cc 33 66 77 01 ef
|
||||
|
||||
We'd draw:
|
||||
|
||||
22 22 22 22 | 11 11 33 33 ; f = 1111, c = 1100
|
||||
22 00 00 22 | 11 11 33 33 ; 9 = 1001, c = 1100
|
||||
22 00 00 22 | 33 33 11 11 ; 9 = 1001, 3 = 0011
|
||||
22 22 22 22 | 33 33 11 11 ; f = 1111, 3 = 0011
|
||||
------------+------------
|
||||
44 55 44 55 | 66 66 66 66 ; a = 1010, 0 = 0000
|
||||
44 55 44 55 | 77 66 66 66 ; a = 1010, 1 = 0001
|
||||
55 44 55 44 | 66 77 77 77 ; 5 = 0101, e = 1110
|
||||
55 44 55 44 | 77 77 77 77 ; 5 = 0101, f = 1111
|
||||
|
||||
I've added a dividing line in the above to clearly delineate the
|
||||
quadrants.
|
||||
|
||||
|
||||
Now, if P0 > P1 then we get 10 more bytes from the data stream:
|
||||
|
||||
B0 B1 B2 B3 P2 P3 B4 B5 B6 B7
|
||||
|
||||
Now, if P2 <= P3, then the first six bytes [P0 P1 B0 B1 B2 B3]
|
||||
represent the left half of the block and the latter six bytes
|
||||
[P2 P3 B4 B5 B6 B7] represent the right half.
|
||||
|
||||
For example:
|
||||
|
||||
22 00 01 37 f7 31 11 66 8c e6 73 31
|
||||
|
||||
yeilds:
|
||||
|
||||
22 22 22 22 | 11 11 11 66 ; 0: 0000 | 8: 1000
|
||||
00 22 22 22 | 11 11 66 66 ; 1: 0001 | C: 1100
|
||||
00 00 22 22 | 11 66 66 66 ; 3: 0011 | e: 1110
|
||||
00 00 00 22 | 11 66 11 66 ; 7: 0111 | 6: 0101
|
||||
00 00 00 00 | 66 66 66 11 ; f: 1111 | 7: 0111
|
||||
00 00 00 22 | 66 66 11 11 ; 7: 0111 | 3: 0011
|
||||
00 00 22 22 | 66 66 11 11 ; 3: 0011 | 3: 0011
|
||||
00 22 22 22 | 66 11 11 11 ; 1: 0001 | 1: 0001
|
||||
|
||||
|
||||
On the other hand, if P0 > P1 and P2 > P3, then
|
||||
[P0 P1 B0 B1 B2 B3] represent the top half of the
|
||||
block and [P2 P3 B4 B5 B6 B7] represent the bottom half.
|
||||
|
||||
For example:
|
||||
|
||||
22 00 cc 66 33 19 66 11 18 24 42 81
|
||||
|
||||
yeilds:
|
||||
|
||||
22 22 00 00 22 22 00 00 ; cc: 11001100
|
||||
22 00 00 22 22 00 00 22 ; 66: 01100110
|
||||
00 00 22 22 00 00 22 22 ; 33: 00110011
|
||||
00 22 22 00 00 22 22 22 ; 19: 00011001
|
||||
-----------------------
|
||||
66 66 66 11 11 66 66 66 ; 18: 00011000
|
||||
66 66 11 66 66 11 66 66 ; 24: 00100100
|
||||
66 11 66 66 66 66 11 66 ; 42: 01000010
|
||||
11 66 66 66 66 66 66 11 ; 81: 10000001
|
||||
*/
|
||||
if ( (*pData)[0] <= (*pData)[1])
|
||||
{
|
||||
// four quadrant case
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
p[0] = *(*pData)++;
|
||||
p[1] = *(*pData)++;
|
||||
pat[0] = *(*pData)++;
|
||||
pat[1] = *(*pData)++;
|
||||
patternQuadrant2Pixels(*pFrame, pat[0], pat[1], p);
|
||||
|
||||
// alternate between moving down and moving up and right
|
||||
if (i & 1)
|
||||
*pFrame += 4 - 4*g_width; // up and right
|
||||
else
|
||||
*pFrame += 4*g_width; // down
|
||||
}
|
||||
}
|
||||
else if ( (*pData)[6] <= (*pData)[7])
|
||||
{
|
||||
// split horizontal
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
if ((i & 1) == 0)
|
||||
{
|
||||
p[0] = *(*pData)++;
|
||||
p[1] = *(*pData)++;
|
||||
}
|
||||
pat[0] = *(*pData)++;
|
||||
pat[1] = *(*pData)++;
|
||||
patternQuadrant2Pixels(*pFrame, pat[0], pat[1], p);
|
||||
|
||||
if (i & 1)
|
||||
*pFrame -= (4*g_width - 4);
|
||||
else
|
||||
*pFrame += 4*g_width;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// split vertical
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
if ((i & 3) == 0)
|
||||
{
|
||||
p[0] = *(*pData)++;
|
||||
p[1] = *(*pData)++;
|
||||
}
|
||||
patternRow2Pixels(*pFrame, *(*pData)++, p);
|
||||
*pFrame += g_width;
|
||||
}
|
||||
*pFrame -= (8*g_width - 8);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x9:
|
||||
/* Similar to the previous 2 encodings, only more complicated. And
|
||||
it will get worse before it gets better. No longer are we dealing
|
||||
with patterns over two pixel values. Now we are dealing with
|
||||
patterns over 4 pixel values with 2 bits assigned to each pixel
|
||||
(or block of pixels).
|
||||
|
||||
So, first on the data stream are our 4 pixel values:
|
||||
|
||||
P0 P1 P2 P3
|
||||
|
||||
Now, if P0 <= P1 AND P2 <= P3, we get 16 bytes of pattern, each
|
||||
2 bits representing a 1x1 pixel (00=P0, 01=P1, 10=P2, 11=P3). The
|
||||
ordering is again left to right and top to bottom. The most
|
||||
significant bits represent the left side at the top, and so on.
|
||||
|
||||
If P0 <= P1 AND P2 > P3, we get 4 bytes of pattern, each 2 bits
|
||||
representing a 2x2 pixel. Ordering is left to right and top to
|
||||
bottom.
|
||||
|
||||
if P0 > P1 AND P2 <= P3, we get 8 bytes of pattern, each 2 bits
|
||||
representing a 2x1 pixel (i.e. 2 pixels wide, and 1 high).
|
||||
|
||||
if P0 > P1 AND P2 > P3, we get 8 bytes of pattern, each 2 bits
|
||||
representing a 1x2 pixel (i.e. 1 pixel wide, and 2 high).
|
||||
*/
|
||||
if ( (*pData)[0] <= (*pData)[1])
|
||||
{
|
||||
if ( (*pData)[2] <= (*pData)[3])
|
||||
{
|
||||
p[0] = *(*pData)++;
|
||||
p[1] = *(*pData)++;
|
||||
p[2] = *(*pData)++;
|
||||
p[3] = *(*pData)++;
|
||||
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
pat[0] = *(*pData)++;
|
||||
pat[1] = *(*pData)++;
|
||||
patternRow4Pixels(*pFrame, pat[0], pat[1], p);
|
||||
*pFrame += g_width;
|
||||
}
|
||||
|
||||
*pFrame -= (8*g_width - 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
p[0] = *(*pData)++;
|
||||
p[1] = *(*pData)++;
|
||||
p[2] = *(*pData)++;
|
||||
p[3] = *(*pData)++;
|
||||
|
||||
patternRow4Pixels2(*pFrame, *(*pData)++, p);
|
||||
*pFrame += 2*g_width;
|
||||
patternRow4Pixels2(*pFrame, *(*pData)++, p);
|
||||
*pFrame += 2*g_width;
|
||||
patternRow4Pixels2(*pFrame, *(*pData)++, p);
|
||||
*pFrame += 2*g_width;
|
||||
patternRow4Pixels2(*pFrame, *(*pData)++, p);
|
||||
*pFrame -= (6*g_width - 8);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( (*pData)[2] <= (*pData)[3])
|
||||
{
|
||||
// draw 2x1 strips
|
||||
p[0] = *(*pData)++;
|
||||
p[1] = *(*pData)++;
|
||||
p[2] = *(*pData)++;
|
||||
p[3] = *(*pData)++;
|
||||
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
pat[0] = *(*pData)++;
|
||||
patternRow4Pixels2x1(*pFrame, pat[0], p);
|
||||
*pFrame += g_width;
|
||||
}
|
||||
|
||||
*pFrame -= (8*g_width - 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
// draw 1x2 strips
|
||||
p[0] = *(*pData)++;
|
||||
p[1] = *(*pData)++;
|
||||
p[2] = *(*pData)++;
|
||||
p[3] = *(*pData)++;
|
||||
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
pat[0] = *(*pData)++;
|
||||
pat[1] = *(*pData)++;
|
||||
patternRow4Pixels(*pFrame, pat[0], pat[1], p);
|
||||
*pFrame += g_width;
|
||||
patternRow4Pixels(*pFrame, pat[0], pat[1], p);
|
||||
*pFrame += g_width;
|
||||
}
|
||||
|
||||
*pFrame -= (8*g_width - 8);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xa:
|
||||
/* Similar to the previous, only a little more complicated.
|
||||
|
||||
We are still dealing with patterns over 4 pixel values with 2 bits
|
||||
assigned to each pixel (or block of pixels).
|
||||
|
||||
So, first on the data stream are our 4 pixel values:
|
||||
|
||||
P0 P1 P2 P3
|
||||
|
||||
Now, if P0 <= P1, the block is divided into 4 quadrants, ordered
|
||||
(as with opcode 0x8) TL, BL, TR, BR. In this case the next data
|
||||
in the data stream should be:
|
||||
|
||||
B0 B1 B2 B3
|
||||
P4 P5 P6 P7 B4 B5 B6 B7
|
||||
P8 P9 P10 P11 B8 B9 B10 B11
|
||||
P12 P13 P14 P15 B12 B13 B14 B15
|
||||
|
||||
Each 2 bits represent a 1x1 pixel (00=P0, 01=P1, 10=P2, 11=P3).
|
||||
The ordering is again left to right and top to bottom. The most
|
||||
significant bits represent the right side at the top, and so on.
|
||||
|
||||
If P0 > P1 then the next data on the data stream is:
|
||||
|
||||
B0 B1 B2 B3 B4 B5 B6 B7
|
||||
P4 P5 P6 P7 B8 B9 B10 B11 B12 B13 B14 B15
|
||||
|
||||
Now, in this case, if P4 <= P5,
|
||||
[P0 P1 P2 P3 B0 B1 B2 B3 B4 B5 B6 B7] represent the left half of
|
||||
the block and the other bytes represent the right half. If P4 >
|
||||
P5, then [P0 P1 P2 P3 B0 B1 B2 B3 B4 B5 B6 B7] represent the top
|
||||
half of the block and the other bytes represent the bottom half.
|
||||
*/
|
||||
if ( (*pData)[0] <= (*pData)[1])
|
||||
{
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
p[0] = *(*pData)++;
|
||||
p[1] = *(*pData)++;
|
||||
p[2] = *(*pData)++;
|
||||
p[3] = *(*pData)++;
|
||||
pat[0] = *(*pData)++;
|
||||
pat[1] = *(*pData)++;
|
||||
pat[2] = *(*pData)++;
|
||||
pat[3] = *(*pData)++;
|
||||
|
||||
patternQuadrant4Pixels(*pFrame, pat[0], pat[1], pat[2], pat[3], p);
|
||||
|
||||
if (i & 1)
|
||||
*pFrame -= (4*g_width - 4);
|
||||
else
|
||||
*pFrame += 4*g_width;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( (*pData)[12] <= (*pData)[13])
|
||||
{
|
||||
// split vertical
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
if ((i&1) == 0)
|
||||
{
|
||||
p[0] = *(*pData)++;
|
||||
p[1] = *(*pData)++;
|
||||
p[2] = *(*pData)++;
|
||||
p[3] = *(*pData)++;
|
||||
}
|
||||
|
||||
pat[0] = *(*pData)++;
|
||||
pat[1] = *(*pData)++;
|
||||
pat[2] = *(*pData)++;
|
||||
pat[3] = *(*pData)++;
|
||||
|
||||
patternQuadrant4Pixels(*pFrame, pat[0], pat[1], pat[2], pat[3], p);
|
||||
|
||||
if (i & 1)
|
||||
*pFrame -= (4*g_width - 4);
|
||||
else
|
||||
*pFrame += 4*g_width;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// split horizontal
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
if ((i&3) == 0)
|
||||
{
|
||||
p[0] = *(*pData)++;
|
||||
p[1] = *(*pData)++;
|
||||
p[2] = *(*pData)++;
|
||||
p[3] = *(*pData)++;
|
||||
}
|
||||
|
||||
pat[0] = *(*pData)++;
|
||||
pat[1] = *(*pData)++;
|
||||
patternRow4Pixels(*pFrame, pat[0], pat[1], p);
|
||||
*pFrame += g_width;
|
||||
}
|
||||
|
||||
*pFrame -= (8*g_width - 8);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xb:
|
||||
/* In this encoding we get raw pixel data in the data stream -- 64
|
||||
bytes of pixel data. 1 byte for each pixel, and in the standard
|
||||
order (l->r, t->b).
|
||||
*/
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
memcpy(*pFrame, *pData, 8);
|
||||
*pFrame += g_width;
|
||||
*pData += 8;
|
||||
*pDataRemain -= 8;
|
||||
}
|
||||
*pFrame -= (8*g_width - 8);
|
||||
break;
|
||||
|
||||
case 0xc:
|
||||
/* In this encoding we get raw pixel data in the data stream -- 16
|
||||
bytes of pixel data. 1 byte for each block of 2x2 pixels, and in
|
||||
the standard order (l->r, t->b).
|
||||
*/
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
for (j=0; j<2; j++)
|
||||
{
|
||||
for (k=0; k<4; k++)
|
||||
{
|
||||
(*pFrame)[2*k] = (*pData)[k];
|
||||
(*pFrame)[2*k+1] = (*pData)[k];
|
||||
}
|
||||
*pFrame += g_width;
|
||||
}
|
||||
*pData += 4;
|
||||
*pDataRemain -= 4;
|
||||
}
|
||||
*pFrame -= (8*g_width - 8);
|
||||
break;
|
||||
|
||||
case 0xd:
|
||||
/* In this encoding we get raw pixel data in the data stream -- 4
|
||||
bytes of pixel data. 1 byte for each block of 4x4 pixels, and in
|
||||
the standard order (l->r, t->b).
|
||||
*/
|
||||
for (i=0; i<2; i++)
|
||||
{
|
||||
for (j=0; j<4; j++)
|
||||
{
|
||||
for (k=0; k<4; k++)
|
||||
{
|
||||
(*pFrame)[k*g_width+j] = (*pData)[0];
|
||||
(*pFrame)[k*g_width+j+4] = (*pData)[1];
|
||||
}
|
||||
}
|
||||
*pFrame += 4*g_width;
|
||||
*pData += 2;
|
||||
*pDataRemain -= 2;
|
||||
}
|
||||
*pFrame -= (8*g_width - 8);
|
||||
break;
|
||||
|
||||
case 0xe:
|
||||
/* This encoding represents a solid 8x8 frame. We get 1 byte of pixel
|
||||
data from the data stream.
|
||||
*/
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
memset(*pFrame, **pData, 8);
|
||||
*pFrame += g_width;
|
||||
}
|
||||
++*pData;
|
||||
--*pDataRemain;
|
||||
*pFrame -= (8*g_width - 8);
|
||||
break;
|
||||
|
||||
case 0xf:
|
||||
/* This encoding represents a "dithered" frame, which is
|
||||
checkerboarded with alternate pixels of two colors. We get 2
|
||||
bytes of pixel data from the data stream, and these bytes are
|
||||
alternated:
|
||||
|
||||
P0 P1 P0 P1 P0 P1 P0 P1
|
||||
P1 P0 P1 P0 P1 P0 P1 P0
|
||||
...
|
||||
P0 P1 P0 P1 P0 P1 P0 P1
|
||||
P1 P0 P1 P0 P1 P0 P1 P0
|
||||
*/
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
for (j=0; j<8; j++)
|
||||
{
|
||||
(*pFrame)[j] = (*pData)[(i+j)&1];
|
||||
}
|
||||
*pFrame += g_width;
|
||||
}
|
||||
*pData += 2;
|
||||
*pDataRemain -= 2;
|
||||
*pFrame -= (8*g_width - 8);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
10
main/movie.c
10
main/movie.c
|
@ -1,4 +1,4 @@
|
|||
/* $Id: movie.c,v 1.14 2003-01-09 00:57:42 btb Exp $ */
|
||||
/* $Id: movie.c,v 1.15 2003-02-12 08:58:38 btb Exp $ */
|
||||
/*
|
||||
THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
|
||||
SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
|
||||
|
@ -17,7 +17,7 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
|
|||
#endif
|
||||
|
||||
#ifdef RCS
|
||||
static char rcsid[] = "$Id: movie.c,v 1.14 2003-01-09 00:57:42 btb Exp $";
|
||||
static char rcsid[] = "$Id: movie.c,v 1.15 2003-02-12 08:58:38 btb Exp $";
|
||||
#endif
|
||||
|
||||
#define DEBUG_LEVEL CON_NORMAL
|
||||
|
@ -282,7 +282,7 @@ int RunMovie(char *filename, int hires_flag, int must_have,int dx,int dy)
|
|||
|
||||
FontHires = FontHiresAvailable && hires_flag;
|
||||
|
||||
mve = mve_open(filehndl);
|
||||
mve = mve_open_filehandle(filehndl);
|
||||
|
||||
mve_bitmap = gr_create_bitmap(w, h); // w, h must match the mve exactly!
|
||||
|
||||
|
@ -364,7 +364,7 @@ int RotateRobot()
|
|||
mveplay_shutdownMovie(Robo_mve);
|
||||
mve_close(Robo_mve);
|
||||
lseek(RoboFile, Robo_filepos, SEEK_SET);
|
||||
Robo_mve = mve_open(RoboFile);
|
||||
Robo_mve = mve_open_filehandle(RoboFile);
|
||||
mveplay_initializeMovie(Robo_mve, Robo_bitmap);
|
||||
}
|
||||
|
||||
|
@ -394,7 +394,7 @@ int InitRobotMovie(char *filename)
|
|||
|
||||
Robo_filepos = lseek(RoboFile, 0, SEEK_CUR);
|
||||
|
||||
Robo_mve = mve_open(RoboFile);
|
||||
Robo_mve = mve_open_filehandle(RoboFile);
|
||||
|
||||
Robo_bitmap = gr_create_bitmap(MenuHires?320:160, MenuHires?200:88);
|
||||
|
||||
|
|
51
main/mve_main.c
Normal file
51
main/mve_main.c
Normal file
|
@ -0,0 +1,51 @@
|
|||
#include <SDL/SDL.h>
|
||||
|
||||
#include "mvelib.h"
|
||||
|
||||
extern int g_spdFactorNum;
|
||||
|
||||
void initializeMovie(MVESTREAM *mve);
|
||||
void playMovie(MVESTREAM *mve);
|
||||
void shutdownMovie(MVESTREAM *mve);
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr, "usage: mveplay filename\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int doPlay(const char *filename)
|
||||
{
|
||||
MVESTREAM *mve = mve_open(filename);
|
||||
if (mve == NULL)
|
||||
{
|
||||
fprintf(stderr, "can't open MVE file '%s'\n", filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
initializeMovie(mve);
|
||||
playMovie(mve);
|
||||
shutdownMovie(mve);
|
||||
|
||||
mve_close(mve);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int c, char **v)
|
||||
{
|
||||
if (c != 2 && c != 3)
|
||||
usage();
|
||||
|
||||
if (c == 3)
|
||||
g_spdFactorNum = atoi(v[2]);
|
||||
|
||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0)
|
||||
{
|
||||
fprintf(stderr, "Couldn't initialize SDL: %s\n",SDL_GetError());
|
||||
exit(1);
|
||||
}
|
||||
atexit(SDL_Quit);
|
||||
|
||||
return doPlay(v[1]);
|
||||
}
|
151
main/mvelib.c
151
main/mvelib.c
|
@ -1,5 +1,8 @@
|
|||
#include <string.h> // for mem* functions
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "mvelib.h"
|
||||
|
||||
|
@ -12,13 +15,16 @@ static const short MVE_HDRCONST3 = 0x1133;
|
|||
* private utility functions
|
||||
*/
|
||||
static short _mve_get_short(unsigned char *data);
|
||||
static unsigned short _mve_get_ushort(unsigned char *data);
|
||||
|
||||
/*
|
||||
* private functions for mvefile
|
||||
*/
|
||||
static MVEFILE *_mvefile_alloc(void);
|
||||
static void _mvefile_free(MVEFILE *movie);
|
||||
static int _mvefile_open(MVEFILE *movie, int filehandle);
|
||||
static void _mvefile_free_filehandle(MVEFILE *movie);
|
||||
static int _mvefile_open(MVEFILE *movie, const char *filename);
|
||||
static int _mvefile_open_filehandle(MVEFILE *movie, int filehandle);
|
||||
static int _mvefile_read_header(MVEFILE *movie);
|
||||
static void _mvefile_set_buffer_size(MVEFILE *movie, int buf_size);
|
||||
static int _mvefile_fetch_next_chunk(MVEFILE *movie);
|
||||
|
@ -28,7 +34,9 @@ static int _mvefile_fetch_next_chunk(MVEFILE *movie);
|
|||
*/
|
||||
static MVESTREAM *_mvestream_alloc(void);
|
||||
static void _mvestream_free(MVESTREAM *movie);
|
||||
static int _mvestream_open(MVESTREAM *movie, int filehandle);
|
||||
static void _mvestream_free_filehandle(MVESTREAM *movie);
|
||||
static int _mvestream_open(MVESTREAM *movie, const char *filename);
|
||||
static int _mvestream_open_filehandle(MVESTREAM *movie, int filehandle);
|
||||
|
||||
/************************************************************
|
||||
* public MVEFILE functions
|
||||
|
@ -37,13 +45,13 @@ static int _mvestream_open(MVESTREAM *movie, int filehandle);
|
|||
/*
|
||||
* open an MVE file
|
||||
*/
|
||||
MVEFILE *mvefile_open(filehandle)
|
||||
MVEFILE *mvefile_open(const char *filename)
|
||||
{
|
||||
MVEFILE *file;
|
||||
|
||||
/* create the file */
|
||||
file = _mvefile_alloc();
|
||||
if (! _mvefile_open(file, filehandle))
|
||||
if (! _mvefile_open(file, filename))
|
||||
{
|
||||
_mvefile_free(file);
|
||||
return NULL;
|
||||
|
@ -65,6 +73,34 @@ MVEFILE *mvefile_open(filehandle)
|
|||
return file;
|
||||
}
|
||||
|
||||
MVEFILE *mvefile_open_filehandle(int filehandle)
|
||||
{
|
||||
MVEFILE *file;
|
||||
|
||||
/* create the file */
|
||||
file = _mvefile_alloc();
|
||||
if (! _mvefile_open_filehandle(file, filehandle))
|
||||
{
|
||||
_mvefile_free_filehandle(file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* initialize the file */
|
||||
_mvefile_set_buffer_size(file, 1024);
|
||||
|
||||
/* verify the file's header */
|
||||
if (! _mvefile_read_header(file))
|
||||
{
|
||||
_mvefile_free_filehandle(file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* now, prefetch the next chunk */
|
||||
_mvefile_fetch_next_chunk(file);
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
/*
|
||||
* close a MVE file
|
||||
*/
|
||||
|
@ -73,6 +109,11 @@ void mvefile_close(MVEFILE *movie)
|
|||
_mvefile_free(movie);
|
||||
}
|
||||
|
||||
void mvefile_close_filehandle(MVEFILE *movie)
|
||||
{
|
||||
_mvefile_free_filehandle(movie);
|
||||
}
|
||||
|
||||
/*
|
||||
* get the size of the next segment
|
||||
*/
|
||||
|
@ -157,7 +198,7 @@ void mvefile_advance_segment(MVEFILE *movie)
|
|||
|
||||
/* else, advance to next segment */
|
||||
movie->next_segment +=
|
||||
(4 + _mve_get_short(movie->cur_chunk + movie->next_segment));
|
||||
(4 + _mve_get_ushort(movie->cur_chunk + movie->next_segment));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -175,7 +216,7 @@ int mvefile_fetch_next_chunk(MVEFILE *movie)
|
|||
/*
|
||||
* open an MVE stream
|
||||
*/
|
||||
MVESTREAM *mve_open(int filehandle)
|
||||
MVESTREAM *mve_open(const char *filename)
|
||||
{
|
||||
MVESTREAM *movie;
|
||||
|
||||
|
@ -183,7 +224,7 @@ MVESTREAM *mve_open(int filehandle)
|
|||
movie = _mvestream_alloc();
|
||||
|
||||
/* open */
|
||||
if (! _mvestream_open(movie, filehandle))
|
||||
if (! _mvestream_open(movie, filename))
|
||||
{
|
||||
_mvestream_free(movie);
|
||||
return NULL;
|
||||
|
@ -192,6 +233,23 @@ MVESTREAM *mve_open(int filehandle)
|
|||
return movie;
|
||||
}
|
||||
|
||||
MVESTREAM *mve_open_filehandle(int filehandle)
|
||||
{
|
||||
MVESTREAM *movie;
|
||||
|
||||
/* allocate */
|
||||
movie = _mvestream_alloc();
|
||||
|
||||
/* open */
|
||||
if (! _mvestream_open_filehandle(movie, filehandle))
|
||||
{
|
||||
_mvestream_free_filehandle(movie);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return movie;
|
||||
}
|
||||
|
||||
/*
|
||||
* close an MVE stream
|
||||
*/
|
||||
|
@ -200,6 +258,11 @@ void mve_close(MVESTREAM *movie)
|
|||
_mvestream_free(movie);
|
||||
}
|
||||
|
||||
void mve_close_filehandle(MVESTREAM *movie)
|
||||
{
|
||||
_mvestream_free_filehandle(movie);
|
||||
}
|
||||
|
||||
/*
|
||||
* set segment type handler
|
||||
*/
|
||||
|
@ -263,7 +326,7 @@ int mve_play_next_chunk(MVESTREAM *movie)
|
|||
static MVEFILE *_mvefile_alloc(void)
|
||||
{
|
||||
MVEFILE *file = (MVEFILE *)malloc(sizeof(MVEFILE));
|
||||
file->stream = 0;
|
||||
file->stream = -1;
|
||||
file->cur_chunk = NULL;
|
||||
file->buf_size = 0;
|
||||
file->cur_fill = 0;
|
||||
|
@ -278,7 +341,28 @@ static MVEFILE *_mvefile_alloc(void)
|
|||
static void _mvefile_free(MVEFILE *movie)
|
||||
{
|
||||
/* free the stream */
|
||||
movie->stream = 0;
|
||||
if (movie->stream != -1)
|
||||
close(movie->stream);
|
||||
movie->stream = -1;
|
||||
|
||||
/* free the buffer */
|
||||
if (movie->cur_chunk)
|
||||
free(movie->cur_chunk);
|
||||
movie->cur_chunk = NULL;
|
||||
|
||||
/* not strictly necessary */
|
||||
movie->buf_size = 0;
|
||||
movie->cur_fill = 0;
|
||||
movie->next_segment = 0;
|
||||
|
||||
/* free the struct */
|
||||
free(movie);
|
||||
}
|
||||
|
||||
static void _mvefile_free_filehandle(MVEFILE *movie)
|
||||
{
|
||||
/* free the stream */
|
||||
movie->stream = -1;
|
||||
|
||||
/* free the buffer */
|
||||
if (movie->cur_chunk)
|
||||
|
@ -297,9 +381,20 @@ static void _mvefile_free(MVEFILE *movie)
|
|||
/*
|
||||
* open the file stream in thie object
|
||||
*/
|
||||
static int _mvefile_open(MVEFILE *file, int filehandle)
|
||||
static int _mvefile_open(MVEFILE *file, const char *filename)
|
||||
{
|
||||
file->stream = open(filename, O_RDONLY);
|
||||
if (file->stream == -1)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _mvefile_open_filehandle(MVEFILE *file, int filehandle)
|
||||
{
|
||||
file->stream = filehandle;
|
||||
if (file->stream == -1)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -312,7 +407,7 @@ static int _mvefile_read_header(MVEFILE *movie)
|
|||
unsigned char buffer[26];
|
||||
|
||||
/* check the file is open */
|
||||
if (movie->stream == 0)
|
||||
if (movie->stream == -1)
|
||||
return 0;
|
||||
|
||||
/* check the file is long enough */
|
||||
|
@ -345,7 +440,7 @@ static void _mvefile_set_buffer_size(MVEFILE *movie, int buf_size)
|
|||
|
||||
/* allocate new buffer */
|
||||
new_len = 100 + buf_size;
|
||||
new_buffer = malloc(new_len);
|
||||
new_buffer = (unsigned char *)malloc(new_len);
|
||||
|
||||
/* copy old data */
|
||||
if (movie->cur_chunk && movie->cur_fill)
|
||||
|
@ -369,7 +464,7 @@ static int _mvefile_fetch_next_chunk(MVEFILE *movie)
|
|||
unsigned short length;
|
||||
|
||||
/* fail if not open */
|
||||
if (movie->stream == 0)
|
||||
if (movie->stream == -1)
|
||||
return 0;
|
||||
|
||||
/* fail if we can't read the next segment descriptor */
|
||||
|
@ -398,6 +493,13 @@ static short _mve_get_short(unsigned char *data)
|
|||
return value;
|
||||
}
|
||||
|
||||
static unsigned short _mve_get_ushort(unsigned char *data)
|
||||
{
|
||||
unsigned short value;
|
||||
value = data[0] | (data[1] << 8);
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
* allocate an MVESTREAM
|
||||
*/
|
||||
|
@ -429,12 +531,31 @@ static void _mvestream_free(MVESTREAM *movie)
|
|||
memset(movie->handlers, 0, sizeof(movie->handlers));
|
||||
}
|
||||
|
||||
static void _mvestream_free_filehandle(MVESTREAM *movie)
|
||||
{
|
||||
/* close MVEFILE */
|
||||
if (movie->movie)
|
||||
mvefile_close_filehandle(movie->movie);
|
||||
movie->movie = NULL;
|
||||
|
||||
/* clear context and handlers */
|
||||
movie->context = NULL;
|
||||
memset(movie->handlers, 0, sizeof(movie->handlers));
|
||||
}
|
||||
|
||||
/*
|
||||
* open an MVESTREAM object
|
||||
*/
|
||||
static int _mvestream_open(MVESTREAM *movie, int filehandle)
|
||||
static int _mvestream_open(MVESTREAM *movie, const char *filename)
|
||||
{
|
||||
movie->movie = mvefile_open(filehandle);
|
||||
movie->movie = mvefile_open(filename);
|
||||
|
||||
return (movie->movie == NULL) ? 0 : 1;
|
||||
}
|
||||
|
||||
static int _mvestream_open_filehandle(MVESTREAM *movie, int filehandle)
|
||||
{
|
||||
movie->movie = mvefile_open_filehandle(filehandle);
|
||||
|
||||
return (movie->movie == NULL) ? 0 : 1;
|
||||
}
|
||||
|
|
1395
main/mveplay.c
1395
main/mveplay.c
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue