1 // JAM format decoder, used by Blood Omnicide
\r
3 typedef struct jamdecodestream_s
\r
8 double info_framerate;
\r
9 unsigned int info_frames;
\r
10 unsigned int info_imagewidth;
\r
11 unsigned int info_imageheight;
\r
14 unsigned char colorsub;
\r
17 // info used durign decoding
\r
18 unsigned char *videopixels;
\r
19 unsigned char *compressed;
\r
20 unsigned char *framedata;
\r
21 unsigned char *prevframedata;
\r
22 unsigned char colormap[768];
\r
23 unsigned int framesize;
\r
24 unsigned int framenum;
\r
26 // channel the sound file is being played on
\r
31 #define JAMDECODEERROR_NONE 0
\r
32 #define JAMDECODEERROR_EOF 1
\r
33 #define JAMDECODEERROR_READERROR 2
\r
34 #define JAMDECODEERROR_BAD_FRAME_HEADER 3
\r
35 #define JAMDECODEERROR_BAD_OUTPUT_SIZE 4
\r
36 #define JAMDECODEERROR_BAD_COLORMAP 5
\r
39 void jam_close(void *stream);
\r
40 unsigned int jam_getwidth(void *stream);
\r
41 unsigned int jam_getheight(void *stream);
\r
42 double jam_getframerate(void *stream);
\r
43 int jam_video(void *stream, void *imagedata, unsigned int Rmask, unsigned int Gmask, unsigned int Bmask, unsigned int bytesperpixel, int imagebytesperrow);
\r
44 void *jam_open(clvideo_t *video, char *filename, const char **errorstring)
\r
46 unsigned char jamHead[16];
\r
48 jamdecodestream_t *s;
\r
51 s = (jamdecodestream_t *)Z_Malloc(sizeof(jamdecodestream_t));
\r
54 if ((file = FS_OpenVirtualFile(filename, false)))
\r
57 if (FS_Read(s->file, &jamHead, 16))
\r
59 if (!memcmp(jamHead, "JAM", 3))
\r
61 s->info_imagewidth = LittleLong(*(jamHead + 4));
\r
62 s->info_imageheight = LittleLong(*(jamHead + 8));
\r
63 s->info_frames = LittleLong(*(jamHead + 12));
\r
64 s->info_framerate = 15;
\r
66 s->colorscale = 0.70;
\r
69 s->framesize = s->info_imagewidth * s->info_imageheight;
\r
70 if (s->framesize > 0)
\r
72 s->compressed = (unsigned char *)Z_Malloc(s->framesize);
\r
73 s->framedata = (unsigned char *)Z_Malloc(s->framesize * 2);
\r
74 s->prevframedata = (unsigned char *)Z_Malloc(s->framesize * 2);
\r
75 s->videopixels = (unsigned char *)Z_Malloc(s->framesize * 4); // bgra, doubleres
\r
76 if (s->compressed != NULL && s->framedata != NULL && s->prevframedata != NULL && s->videopixels != NULL)
\r
80 namelen = strlen(filename) + 10;
\r
81 wavename = (char *)Z_Malloc(namelen);
\r
86 FS_StripExtension(filename, wavename, namelen);
\r
87 strlcat(wavename, ".wav", namelen);
\r
88 sfx = S_PrecacheSound(wavename, false, false);
\r
90 s->sndchan = S_StartSound (-1, 0, sfx, vec3_origin, 1.0f, 0);
\r
96 // set the module functions
\r
98 video->close = jam_close;
\r
99 video->getwidth = jam_getwidth;
\r
100 video->getheight = jam_getheight;
\r
101 video->getframerate = jam_getframerate;
\r
102 video->decodeframe = jam_video;
\r
105 else if (errorstring != NULL)
\r
106 *errorstring = "unable to allocate memory for stream info structure";
\r
107 if (s->compressed != NULL)
\r
108 Z_Free(s->compressed);
\r
109 if (s->framedata != NULL)
\r
110 Z_Free(s->framedata);
\r
111 if (s->prevframedata != NULL)
\r
112 Z_Free(s->prevframedata);
\r
113 if (s->videopixels != NULL)
\r
114 Z_Free(s->videopixels);
\r
116 else if (errorstring != NULL)
\r
117 *errorstring = "bad framesize";
\r
119 else if (errorstring != NULL)
\r
120 *errorstring = "not JAM videofile";
\r
122 else if (errorstring != NULL)
\r
123 *errorstring = "unexpected EOF";
\r
126 else if (errorstring != NULL)
\r
127 *errorstring = "unable to open videofile";
\r
130 else if (errorstring != NULL)
\r
131 *errorstring = "unable to allocate memory for stream info structure";
\r
136 void jam_close(void *stream)
\r
138 jamdecodestream_t *s = (jamdecodestream_t *)stream;
\r
141 Z_Free(s->compressed);
\r
142 Z_Free(s->framedata);
\r
143 Z_Free(s->prevframedata);
\r
144 Z_Free(s->videopixels);
\r
145 if (s->sndchan != -1)
\r
146 S_StopChannel(s->sndchan, true);
\r
152 // returns the width of the image data
\r
153 unsigned int jam_getwidth(void *stream)
\r
155 jamdecodestream_t *s = (jamdecodestream_t *)stream;
\r
157 return s->info_imagewidth * 2;
\r
158 return s->info_imagewidth;
\r
161 // returns the height of the image data
\r
162 unsigned int jam_getheight(void *stream)
\r
164 jamdecodestream_t *s = (jamdecodestream_t *)stream;
\r
166 return s->info_imageheight * 2;
\r
167 return s->info_imageheight;
\r
170 // returns the framerate of the stream
\r
171 double jam_getframerate(void *stream)
\r
173 jamdecodestream_t *s = (jamdecodestream_t *)stream;
\r
174 return s->info_framerate;
\r
178 // decode JAM frame
\r
179 void jam_decodeframe(unsigned char *inbuf, unsigned char *outbuf, unsigned char *prevbuf, int outsize, int frametype)
\r
181 unsigned char *srcptr, *destptr, *prevptr;
\r
184 unsigned short int bits;
\r
187 unsigned char *back;
\r
193 bytesleft = outsize;
\r
195 if (frametype == 2)
\r
197 memcpy(outbuf, inbuf, outsize);
\r
200 while(bytesleft > 0)
\r
202 memcpy(&mark, srcptr, 4);
\r
204 for(i=0; i<32 && bytesleft > 0; i++,mark=mark>>1)
\r
208 *destptr = *srcptr;
\r
216 bits = srcptr[0] + 256*srcptr[1];
\r
217 rep = (bits >> 11) + 3;
\r
220 backoffs = 0x821 - (bits & 0x7ff);
\r
221 back = destptr - backoffs;
\r
225 backoffs = 0x400 - (bits & 0x7ff);
\r
226 back = prevptr - backoffs;
\r
229 memcpy(destptr, back, rep);
\r
238 // decodes a video frame to the supplied output pixels
\r
239 int jam_video(void *stream, void *imagedata, unsigned int Rmask, unsigned int Gmask, unsigned int Bmask, unsigned int bytesperpixel, int imagebytesperrow)
\r
241 unsigned char frameHead[16], *b;
\r
242 unsigned int compsize, outsize, i, j;
\r
243 jamdecodestream_t *s = (jamdecodestream_t *)stream;
\r
245 s->error = DPVSIMPLEDECODEERROR_NONE;
\r
246 if (s->framenum < s->info_frames)
\r
249 if (FS_Read(s->file, &frameHead, 16))
\r
251 compsize = LittleLong(*(frameHead + 8)) - 16;
\r
252 outsize = LittleLong(*(frameHead + 12));
\r
253 if (compsize < 0 || compsize > s->framesize || outsize < 0 || outsize > s->framesize)
\r
254 s->error = JAMDECODEERROR_BAD_FRAME_HEADER;
\r
255 else if (FS_Read(s->file, s->compressed, compsize))
\r
257 // palette goes interleaved with special flag
\r
258 if (frameHead[0] == 2)
\r
260 if (compsize == 768)
\r
262 memcpy(s->colormap, s->compressed, 768);
\r
263 for(i = 0; i < 768; i++)
\r
264 s->colormap[i] = (unsigned char)(bound(0, (s->colormap[i] * s->colorscale) - s->colorsub, 255));
\r
268 // s->error = JAMDECODEERROR_BAD_COLORMAP;
\r
273 // shift buffers to provide current and previous one, decode
\r
274 b = s->prevframedata;
\r
275 s->prevframedata = s->framedata;
\r
277 jam_decodeframe(s->compressed, s->framedata, s->prevframedata, outsize, frameHead[4]);
\r
278 // make 32bit imagepixels from 8bit palettized frame
\r
280 b = s->videopixels;
\r
282 b = (unsigned char *)imagedata;
\r
283 for(i = 0; i < s->framesize; i++)
\r
286 *b++ = s->colormap[s->framedata[i]*3 + 2];
\r
287 *b++ = s->colormap[s->framedata[i]*3 + 1];
\r
288 *b++ = s->colormap[s->framedata[i]*3];
\r
294 for (i = 0; i < s->info_imageheight; i++)
\r
296 b = (unsigned char *)imagedata + (s->info_imagewidth*2*4)*(i*2);
\r
297 for (j = 0; j < s->info_imagewidth; j++)
\r
299 *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4];
\r
300 *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 1];
\r
301 *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 2];
\r
302 *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 3];
\r
304 *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4];
\r
305 *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 1];
\r
306 *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 2];
\r
307 *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 3];
\r
309 b = (unsigned char *)imagedata + (s->info_imagewidth*2*4)*(i*2 + 1);
\r
310 for (j = 0; j < s->info_imagewidth; j++)
\r
312 *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4];
\r
313 *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 1];
\r
314 *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 2];
\r
315 *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 3];
\r
317 *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4];
\r
318 *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 1];
\r
319 *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 2];
\r
320 *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 3];
\r
326 for (i = 0; i < s->info_imageheight; i++)
\r
328 b = (unsigned char *)imagedata + (s->info_imagewidth * 4 * 2 * 2 * i);
\r
329 for (j = 0; j < s->info_imagewidth; j++)
\r
331 b[0] = b[0] * s->stipple;
\r
332 b[1] = b[1] * s->stipple;
\r
333 b[2] = b[2] * s->stipple;
\r
335 b[0] = b[0] * s->stipple;
\r
336 b[1] = b[1] * s->stipple;
\r
337 b[2] = b[2] * s->stipple;
\r
347 s->error = JAMDECODEERROR_READERROR;
\r
350 s->error = JAMDECODEERROR_READERROR;
\r
353 s->error = DPVSIMPLEDECODEERROR_EOF;
\r