1 // JAM format decoder, used by Blood Omnicide
4 //#define JAM_USELIBAVCODECSCALE
7 typedef struct jamdecodestream_s
10 double info_framerate;
11 unsigned int info_frames;
12 unsigned int info_imagewidth;
13 unsigned int info_imageheight;
14 double info_aspectratio;
16 unsigned char colorsub;
18 // info used during decoding
20 unsigned char *frame_prev;
21 unsigned char frame_palette[768];
22 unsigned char *frame_compressed;
23 unsigned int framesize;
24 unsigned int framenum;
27 #ifdef JAM_USELIBAVCODECSCALE
28 unsigned char *frame_output_buffer;
29 AVFrame *frame_output;
30 AVFrame *frame_output_scale;
31 unsigned int framewidth;
32 unsigned int frameheight;
35 // channel the sound file is being played on
41 void jam_close(void *stream);
42 unsigned int jam_getwidth(void *stream);
43 unsigned int jam_getheight(void *stream);
44 double jam_getframerate(void *stream);
45 double jam_getaspectratio(void *stream);
46 int jam_video(void *stream, void *imagedata, unsigned int Rmask, unsigned int Gmask, unsigned int Bmask, unsigned int bytesperpixel, int imagebytesperrow);
47 void *jam_open(clvideo_t *video, char *filename, const char **errorstring)
53 // allocate stream structure
54 s = (jamdecodestream_t *)Z_Malloc(sizeof(jamdecodestream_t));
55 memset(s, 0, sizeof(jamdecodestream_t));
58 *errorstring = "unable to allocate memory for stream info structure";
64 s->file = FS_OpenVirtualFile(filename, true);
67 *errorstring = "unable to open videofile";
73 if (!FS_Read(s->file, jamHead, 16))
75 *errorstring = "JamDecoder: unexpected EOF reading header";
79 if (memcmp(jamHead, "JAM", 4))
81 *errorstring = "JamDecoder: not a JAM file";
86 s->info_imagewidth = LittleLong(*(jamHead + 4));
87 s->info_imageheight = LittleLong(*(jamHead + 8));
88 s->info_frames = LittleLong(*(jamHead + 12)) - 1;
89 s->info_framerate = 15;
90 s->info_aspectratio = (double)s->info_imagewidth / (double)s->info_imageheight;
93 s->framesize = s->info_imagewidth * s->info_imageheight;
95 // allocate frame input/output
98 *errorstring = "JamDecoder: bad framesize";
102 s->frame = (unsigned char *)Z_Malloc(s->framesize * 2);
103 s->frame_prev = (unsigned char *)Z_Malloc(s->framesize * 2);
104 s->frame_compressed = (unsigned char *)Z_Malloc(s->framesize);
105 if (s->frame_compressed == NULL || s->frame == NULL || s->frame_prev == NULL)
107 *errorstring = "JamDecoder: unable to allocate memory for video decoder";
112 // scale support provided by libavcodec
113 #ifdef JAM_USELIBAVCODECSCALE
114 s->framewidth = s->info_imagewidth;
115 s->frameheight = s->info_imageheight;
118 if (cl_video_libavcodec_minwidth.integer > 0)
119 s->info_imagewidth = max(s->info_imagewidth, (unsigned int)cl_video_libavcodec_minwidth.integer);
120 if (cl_video_libavcodec_minheight.integer > 0)
121 s->info_imageheight = max(s->info_imageheight, (unsigned int)cl_video_libavcodec_minheight.integer);
124 s->frame_output_buffer = (unsigned char *)Z_Malloc(s->framesize * 4);
125 s->frame_output = AvCodec_AllocFrame();
126 s->frame_output_scale = AvCodec_AllocFrame();
127 if (!s->frame_output_buffer || !s->frame_output || !s->frame_output_scale)
129 *errorstring = "JamDecoder: failed to allocate LibAvcodec frame";
137 // set the module functions
139 video->close = jam_close;
140 video->getwidth = jam_getwidth;
141 video->getheight = jam_getheight;
142 video->getframerate = jam_getframerate;
143 video->decodeframe = jam_video;
144 video->getaspectratio = jam_getaspectratio;
148 namelen = strlen(filename) + 10;
149 wavename = (char *)Z_Malloc(namelen);
153 FS_StripExtension(filename, wavename, namelen);
154 strlcat(wavename, ".wav", namelen);
155 sfx = S_PrecacheSound(wavename, false, false);
157 s->sndchan = S_StartSound (-1, 0, sfx, vec3_origin, 1.0f, 0);
167 void jam_close(void *stream)
169 jamdecodestream_t *s = (jamdecodestream_t *)stream;
172 if (s->frame_compressed)
173 Z_Free(s->frame_compressed);
174 s->frame_compressed = NULL;
179 Z_Free(s->frame_prev);
180 s->frame_prev = NULL;
181 if (s->sndchan != -1)
182 S_StopChannel(s->sndchan, true, true);
187 #ifdef JAM_USELIBAVCODECSCALE
188 if (s->frame_output_buffer)
189 Z_Free(s->frame_output_buffer);
190 s->frame_output_buffer = NULL;
192 AvUtil_Free(s->frame_output);
193 s->frame_output = NULL;
194 if (s->frame_output_scale)
195 AvUtil_Free(s->frame_output_scale);
196 s->frame_output_scale = NULL;
201 // returns the width of the image data
202 unsigned int jam_getwidth(void *stream)
204 jamdecodestream_t *s = (jamdecodestream_t *)stream;
205 return s->info_imagewidth;
208 // returns the height of the image data
209 unsigned int jam_getheight(void *stream)
211 jamdecodestream_t *s = (jamdecodestream_t *)stream;
212 return s->info_imageheight;
215 // returns the framerate of the stream
216 double jam_getframerate(void *stream)
218 jamdecodestream_t *s = (jamdecodestream_t *)stream;
219 return s->info_framerate;
222 // returns aspect ration of the stream
223 double jam_getaspectratio(void *stream)
225 jamdecodestream_t *s = (jamdecodestream_t *)stream;
226 return s->info_aspectratio;
230 static void jam_decodeframe(unsigned char *inbuf, unsigned char *outbuf, unsigned char *prevbuf, int outsize, int frametype)
232 unsigned char *srcptr, *destptr, *prevptr;
235 unsigned short int bits;
248 memcpy(outbuf, inbuf, outsize);
253 memcpy(&mark, srcptr, 4);
255 for(i=0; i<32 && bytesleft > 0; i++,mark=mark>>1)
267 bits = srcptr[0] + 256*srcptr[1];
268 rep = (bits >> 11) + 3;
271 backoffs = 0x821 - (bits & 0x7ff);
272 back = destptr - backoffs;
276 backoffs = 0x400 - (bits & 0x7ff);
277 back = prevptr - backoffs;
280 memcpy(destptr, back, rep);
289 // decodes a video frame to the supplied output pixels
290 int jam_video(void *stream, void *imagedata, unsigned int Rmask, unsigned int Gmask, unsigned int Bmask, unsigned int bytesperpixel, int imagebytesperrow)
292 unsigned char frameHead[16], *b;
293 unsigned int compsize, outsize, i;
294 jamdecodestream_t *s = (jamdecodestream_t *)stream;
297 if (s->framenum >= s->info_frames)
303 if (!FS_Read(s->file, &frameHead, 16))
305 Con_Printf("JamDecoder: unexpected EOF on frame %i\n", s->framenum);
308 compsize = LittleLong(*(frameHead + 8)) - 16;
309 outsize = LittleLong(*(frameHead + 12));
310 if (compsize > s->framesize || outsize > s->framesize)
312 Con_Printf("JamDecoder: got bogus header on frame %i\n", s->framenum);
316 // read frame contents
317 if (!FS_Read(s->file, s->frame_compressed, compsize))
319 Con_Printf("JamDecoder: unexpected EOF on frame %i\n", s->framenum);
323 // palette goes interleaved with special flag
324 if (frameHead[0] == 2)
328 memcpy(s->frame_palette, s->frame_compressed, 768);
329 for(i = 0; i < 768; i++)
330 s->frame_palette[i] = (unsigned char)(bound(0, (s->frame_palette[i] * s->colorscale) - s->colorsub, 255));
337 // shift buffers to provide current and previous one, decode
339 s->frame_prev = s->frame;
341 jam_decodeframe(s->frame_compressed, s->frame, s->frame_prev, outsize, frameHead[4]);
342 #ifdef JAM_USELIBAVCODECSCALE
343 // make BGRA imagepixels from 8bit palettized frame
344 b = (unsigned char *)s->frame_output_buffer;
345 for(i = 0; i < s->framesize; i++)
347 *b++ = s->frame_palette[s->frame[i]*3 + 2];
348 *b++ = s->frame_palette[s->frame[i]*3 + 1];
349 *b++ = s->frame_palette[s->frame[i]*3];
353 AvCodec_FillPicture((AVPicture *)s->frame_output, (uint8_t *)s->frame_output_buffer, PIX_FMT_BGRA, s->framewidth, s->frameheight);
354 AvCodec_FillPicture((AVPicture *)s->frame_output_scale, (uint8_t *)imagedata, PIX_FMT_BGRA, s->info_imagewidth, s->info_imageheight);
355 SwsContext *scale_context = SwScale_GetCachedContext(NULL, s->framewidth, s->frameheight, PIX_FMT_BGRA, s->info_imagewidth, s->info_imageheight, PIX_FMT_BGRA, libavcodec_scalers[max(0, min(LIBAVCODEC_SCALERS, cl_video_libavcodec_scaler.integer))], NULL, NULL, NULL);
358 Con_Printf("JamDecoder: LibAvcodec: error creating scale context frame %i\n", s->framenum);
361 if (!SwScale_Scale(scale_context, s->frame_output->data, s->frame_output->linesize, 0, s->frameheight, s->frame_output_scale->data, s->frame_output_scale->linesize))
362 Con_Printf("JamDecoder: LibAvcodec : error scaling frame\n", s->framenum);
363 SwScale_FreeContext(scale_context);
365 // make BGRA imagepixels from 8bit palettized frame
366 b = (unsigned char *)imagedata;
367 for(i = 0; i < s->framesize; i++)
370 *b++ = s->frame_palette[s->frame[i]*3 + 2];
371 *b++ = s->frame_palette[s->frame[i]*3 + 1];
372 *b++ = s->frame_palette[s->frame[i]*3];