]> icculus.org git repositories - divverent/darkplaces.git/blob - dpvsimpledecode.c
Merge branch 'master' into blub/dp1
[divverent/darkplaces.git] / dpvsimpledecode.c
1
2 #include "quakedef.h"
3 #include "dpvsimpledecode.h"
4
5 #define HZREADERROR_OK 0
6 #define HZREADERROR_EOF 1
7 #define HZREADERROR_MALLOCFAILED 2
8
9 //#define HZREADBLOCKSIZE 16000
10 #define HZREADBLOCKSIZE 1048576
11
12 typedef struct hz_bitstream_read_s
13 {
14         qfile_t *file;
15         int endoffile;
16 }
17 hz_bitstream_read_t;
18
19 typedef struct hz_bitstream_readblock_s
20 {
21         struct hz_bitstream_readblock_s *next;
22         unsigned int size;
23         unsigned char data[HZREADBLOCKSIZE];
24 }
25 hz_bitstream_readblock_t;
26
27 typedef struct hz_bitstream_readblocks_s
28 {
29         hz_bitstream_readblock_t *blocks;
30         hz_bitstream_readblock_t *current;
31         unsigned int position;
32         unsigned int store;
33         int count;
34 }
35 hz_bitstream_readblocks_t;
36
37 hz_bitstream_read_t *hz_bitstream_read_open(char *filename)
38 {
39         qfile_t *file;
40         hz_bitstream_read_t *stream;
41         if ((file = FS_OpenVirtualFile(filename, false)))
42         {
43                 stream = (hz_bitstream_read_t *)Z_Malloc(sizeof(hz_bitstream_read_t));
44                 memset(stream, 0, sizeof(*stream));
45                 stream->file = file;
46                 return stream;
47         }
48         else
49                 return NULL;
50 }
51
52 void hz_bitstream_read_close(hz_bitstream_read_t *stream)
53 {
54         if (stream)
55         {
56                 FS_Close(stream->file);
57                 Z_Free(stream);
58         }
59 }
60
61 hz_bitstream_readblocks_t *hz_bitstream_read_blocks_new(void)
62 {
63         hz_bitstream_readblocks_t *blocks;
64         blocks = (hz_bitstream_readblocks_t *)Z_Malloc(sizeof(hz_bitstream_readblocks_t));
65         if (blocks == NULL)
66                 return NULL;
67         memset(blocks, 0, sizeof(hz_bitstream_readblocks_t));
68         return blocks;
69 }
70
71 void hz_bitstream_read_blocks_free(hz_bitstream_readblocks_t *blocks)
72 {
73         hz_bitstream_readblock_t *b, *n;
74         if (blocks == NULL)
75                 return;
76         for (b = blocks->blocks;b;b = n)
77         {
78                 n = b->next;
79                 Z_Free(b);
80         }
81         Z_Free(blocks);
82 }
83
84 void hz_bitstream_read_flushbits(hz_bitstream_readblocks_t *blocks)
85 {
86         blocks->store = 0;
87         blocks->count = 0;
88 }
89
90 int hz_bitstream_read_blocks_read(hz_bitstream_readblocks_t *blocks, hz_bitstream_read_t *stream, unsigned int size)
91 {
92         int s;
93         hz_bitstream_readblock_t *b, *p;
94         s = size;
95         p = NULL;
96         b = blocks->blocks;
97         while (s > 0)
98         {
99                 if (b == NULL)
100                 {
101                         b = (hz_bitstream_readblock_t *)Z_Malloc(sizeof(hz_bitstream_readblock_t));
102                         if (b == NULL)
103                                 return HZREADERROR_MALLOCFAILED;
104                         b->next = NULL;
105                         b->size = 0;
106                         if (p != NULL)
107                                 p->next = b;
108                         else
109                                 blocks->blocks = b;
110                 }
111                 if (s > HZREADBLOCKSIZE)
112                         b->size = HZREADBLOCKSIZE;
113                 else
114                         b->size = s;
115                 s -= b->size;
116                 if (FS_Read(stream->file, b->data, b->size) != (fs_offset_t)b->size)
117                 {
118                         stream->endoffile = 1;
119                         break;
120                 }
121                 p = b;
122                 b = b->next;
123         }
124         while (b)
125         {
126                 b->size = 0;
127                 b = b->next;
128         }
129         blocks->current = blocks->blocks;
130         blocks->position = 0;
131         hz_bitstream_read_flushbits(blocks);
132         if (stream->endoffile)
133                 return HZREADERROR_EOF;
134         return HZREADERROR_OK;
135 }
136
137 unsigned int hz_bitstream_read_blocks_getbyte(hz_bitstream_readblocks_t *blocks)
138 {
139         while (blocks->current != NULL && blocks->position >= blocks->current->size)
140         {
141                 blocks->position = 0;
142                 blocks->current = blocks->current->next;
143         }
144         if (blocks->current == NULL)
145                 return 0;
146         return blocks->current->data[blocks->position++];
147 }
148
149 int hz_bitstream_read_bit(hz_bitstream_readblocks_t *blocks)
150 {
151         if (!blocks->count)
152         {
153                 blocks->count += 8;
154                 blocks->store <<= 8;
155                 blocks->store |= hz_bitstream_read_blocks_getbyte(blocks) & 0xFF;
156         }
157         blocks->count--;
158         return (blocks->store >> blocks->count) & 1;
159 }
160
161 unsigned int hz_bitstream_read_bits(hz_bitstream_readblocks_t *blocks, int size)
162 {
163         unsigned int num = 0;
164         // we can only handle about 24 bits at a time safely
165         // (there might be up to 7 bits more than we need in the bit store)
166         if (size > 24)
167         {
168                 size -= 8;
169                 num |= hz_bitstream_read_bits(blocks, 8) << size;
170         }
171         while (blocks->count < size)
172         {
173                 blocks->count += 8;
174                 blocks->store <<= 8;
175                 blocks->store |= hz_bitstream_read_blocks_getbyte(blocks) & 0xFF;
176         }
177         blocks->count -= size;
178         num |= (blocks->store >> blocks->count) & ((1 << size) - 1);
179         return num;
180 }
181
182 unsigned int hz_bitstream_read_byte(hz_bitstream_readblocks_t *blocks)
183 {
184         return hz_bitstream_read_blocks_getbyte(blocks);
185 }
186
187 unsigned int hz_bitstream_read_short(hz_bitstream_readblocks_t *blocks)
188 {
189         return (hz_bitstream_read_byte(blocks) << 8)
190              | (hz_bitstream_read_byte(blocks));
191 }
192
193 unsigned int hz_bitstream_read_int(hz_bitstream_readblocks_t *blocks)
194 {
195         return (hz_bitstream_read_byte(blocks) << 24)
196              | (hz_bitstream_read_byte(blocks) << 16)
197              | (hz_bitstream_read_byte(blocks) << 8)
198              | (hz_bitstream_read_byte(blocks));
199 }
200
201 void hz_bitstream_read_bytes(hz_bitstream_readblocks_t *blocks, void *outdata, unsigned int size)
202 {
203         unsigned char *out;
204         out = (unsigned char *)outdata;
205         while (size--)
206                 *out++ = hz_bitstream_read_byte(blocks);
207 }
208
209 #define BLOCKSIZE 8
210
211 typedef struct dpvsimpledecodestream_s
212 {
213         hz_bitstream_read_t *bitstream;
214         hz_bitstream_readblocks_t *framedatablocks;
215
216         int error;
217
218         double info_framerate;
219         unsigned int info_frames;
220
221         unsigned int info_imagewidth;
222         unsigned int info_imageheight;
223         unsigned int info_imagebpp;
224         unsigned int info_imageRloss;
225         unsigned int info_imageRmask;
226         unsigned int info_imageRshift;
227         unsigned int info_imageGloss;
228         unsigned int info_imageGmask;
229         unsigned int info_imageGshift;
230         unsigned int info_imageBloss;
231         unsigned int info_imageBmask;
232         unsigned int info_imageBshift;
233         unsigned int info_imagesize;
234
235         // current video frame (needed because of delta compression)
236         int videoframenum;
237         // current video frame data (needed because of delta compression)
238         unsigned int *videopixels;
239
240         // channel the sound file is being played on
241         int sndchan;
242 }
243 dpvsimpledecodestream_t;
244
245 static int dpvsimpledecode_setpixelformat(dpvsimpledecodestream_t *s, unsigned int Rmask, unsigned int Gmask, unsigned int Bmask, unsigned int bytesperpixel)
246 {
247         int Rshift, Rbits, Gshift, Gbits, Bshift, Bbits;
248         if (!Rmask)
249         {
250                 s->error = DPVSIMPLEDECODEERROR_INVALIDRMASK;
251                 return s->error;
252         }
253         if (!Gmask)
254         {
255                 s->error = DPVSIMPLEDECODEERROR_INVALIDGMASK;
256                 return s->error;
257         }
258         if (!Bmask)
259         {
260                 s->error = DPVSIMPLEDECODEERROR_INVALIDBMASK;
261                 return s->error;
262         }
263         if (Rmask & Gmask || Rmask & Bmask || Gmask & Bmask)
264         {
265                 s->error = DPVSIMPLEDECODEERROR_COLORMASKSOVERLAP;
266                 return s->error;
267         }
268         switch (bytesperpixel)
269         {
270         case 2:
271                 if ((Rmask | Gmask | Bmask) > 65536)
272                 {
273                         s->error = DPVSIMPLEDECODEERROR_COLORMASKSEXCEEDBPP;
274                         return s->error;
275                 }
276                 break;
277         case 4:
278                 break;
279         default:
280                 s->error = DPVSIMPLEDECODEERROR_UNSUPPORTEDBPP;
281                 return s->error;
282         }
283         for (Rshift = 0;!(Rmask & 1);Rshift++, Rmask >>= 1);
284         for (Gshift = 0;!(Gmask & 1);Gshift++, Gmask >>= 1);
285         for (Bshift = 0;!(Bmask & 1);Bshift++, Bmask >>= 1);
286         if (((Rmask + 1) & Rmask) != 0)
287         {
288                 s->error = DPVSIMPLEDECODEERROR_INVALIDRMASK;
289                 return s->error;
290         }
291         if (((Gmask + 1) & Gmask) != 0)
292         {
293                 s->error = DPVSIMPLEDECODEERROR_INVALIDGMASK;
294                 return s->error;
295         }
296         if (((Bmask + 1) & Bmask) != 0)
297         {
298                 s->error = DPVSIMPLEDECODEERROR_INVALIDBMASK;
299                 return s->error;
300         }
301         for (Rbits = 0;Rmask & 1;Rbits++, Rmask >>= 1);
302         for (Gbits = 0;Gmask & 1;Gbits++, Gmask >>= 1);
303         for (Bbits = 0;Bmask & 1;Bbits++, Bmask >>= 1);
304         if (Rbits > 8)
305         {
306                 Rshift += (Rbits - 8);
307                 Rbits = 8;
308         }
309         if (Gbits > 8)
310         {
311                 Gshift += (Gbits - 8);
312                 Gbits = 8;
313         }
314         if (Bbits > 8)
315         {
316                 Bshift += (Bbits - 8);
317                 Bbits = 8;
318         }
319         s->info_imagebpp = bytesperpixel;
320         s->info_imageRloss = 16 + (8 - Rbits);
321         s->info_imageGloss =  8 + (8 - Gbits);
322         s->info_imageBloss =  0 + (8 - Bbits);
323         s->info_imageRmask = (1 << Rbits) - 1;
324         s->info_imageGmask = (1 << Gbits) - 1;
325         s->info_imageBmask = (1 << Bbits) - 1;
326         s->info_imageRshift = Rshift;
327         s->info_imageGshift = Gshift;
328         s->info_imageBshift = Bshift;
329         s->info_imagesize = s->info_imagewidth * s->info_imageheight * s->info_imagebpp;
330         return s->error;
331 }
332
333 // opening and closing streams
334
335 // opens a stream
336 void *dpvsimpledecode_open(char *filename, char **errorstring)
337 {
338         dpvsimpledecodestream_t *s;
339         char t[8], *wavename;
340         if (errorstring != NULL)
341                 *errorstring = NULL;
342         s = (dpvsimpledecodestream_t *)Z_Malloc(sizeof(dpvsimpledecodestream_t));
343         if (s != NULL)
344         {
345                 s->bitstream = hz_bitstream_read_open(filename);
346                 if (s->bitstream != NULL)
347                 {
348                         // check file identification
349                         s->framedatablocks = hz_bitstream_read_blocks_new();
350                         if (s->framedatablocks != NULL)
351                         {
352                                 hz_bitstream_read_blocks_read(s->framedatablocks, s->bitstream, 8);
353                                 hz_bitstream_read_bytes(s->framedatablocks, t, 8);
354                                 if (!memcmp(t, "DPVideo", 8))
355                                 {
356                                         // check version number
357                                         hz_bitstream_read_blocks_read(s->framedatablocks, s->bitstream, 2);
358                                         if (hz_bitstream_read_short(s->framedatablocks) == 1)
359                                         {
360                                                 hz_bitstream_read_blocks_read(s->framedatablocks, s->bitstream, 12);
361                                                 s->info_imagewidth = hz_bitstream_read_short(s->framedatablocks);
362                                                 s->info_imageheight = hz_bitstream_read_short(s->framedatablocks);
363                                                 s->info_framerate = (double) hz_bitstream_read_int(s->framedatablocks) * (1.0 / 65536.0);
364
365                                                 if (s->info_framerate > 0.0)
366                                                 {
367                                                         s->videopixels = (unsigned int *)Z_Malloc(s->info_imagewidth * s->info_imageheight * sizeof(*s->videopixels));
368                                                         if (s->videopixels != NULL)
369                                                         {
370                                                                 size_t namelen;
371
372                                                                 namelen = strlen(filename) + 10;
373                                                                 wavename = (char *)Z_Malloc(namelen);
374                                                                 if (wavename)
375                                                                 {
376                                                                         sfx_t* sfx;
377
378                                                                         FS_StripExtension(filename, wavename, namelen);
379                                                                         strlcat(wavename, ".wav", namelen);
380                                                                         sfx = S_PrecacheSound (wavename, false, false);
381                                                                         if (sfx != NULL)
382                                                                                 s->sndchan = S_StartSound (-1, 0, sfx, vec3_origin, 1.0f, 0);
383                                                                         else
384                                                                                 s->sndchan = -1;
385                                                                         Z_Free(wavename);
386                                                                 }
387                                                                 // all is well...
388                                                                 s->videoframenum = -10000;
389                                                                 return s;
390                                                         }
391                                                         else if (errorstring != NULL)
392                                                                 *errorstring = "unable to allocate video image buffer";
393                                                 }
394                                                 else if (errorstring != NULL)
395                                                         *errorstring = "error in video info chunk";
396                                         }
397                                         else if (errorstring != NULL)
398                                                 *errorstring = "read error";
399                                 }
400                                 else if (errorstring != NULL)
401                                         *errorstring = "not a dpvideo file";
402                                 hz_bitstream_read_blocks_free(s->framedatablocks);
403                         }
404                         else if (errorstring != NULL)
405                                 *errorstring = "unable to allocate memory for reading buffer";
406                         hz_bitstream_read_close(s->bitstream);
407                 }
408                 else if (errorstring != NULL)
409                         *errorstring = "unable to open file";
410                 Z_Free(s);
411         }
412         else if (errorstring != NULL)
413                 *errorstring = "unable to allocate memory for stream info structure";
414         return NULL;
415 }
416
417 // closes a stream
418 void dpvsimpledecode_close(void *stream)
419 {
420         dpvsimpledecodestream_t *s = (dpvsimpledecodestream_t *)stream;
421         if (s == NULL)
422                 return;
423         if (s->videopixels)
424                 Z_Free(s->videopixels);
425         if (s->sndchan != -1)
426                 S_StopChannel (s->sndchan, true);
427         if (s->framedatablocks)
428                 hz_bitstream_read_blocks_free(s->framedatablocks);
429         if (s->bitstream)
430                 hz_bitstream_read_close(s->bitstream);
431         Z_Free(s);
432 }
433
434 // utilitarian functions
435
436 // returns the current error number for the stream, and resets the error
437 // number to DPVSIMPLEDECODEERROR_NONE
438 // if the supplied string pointer variable is not NULL, it will be set to the
439 // error message
440 int dpvsimpledecode_error(void *stream, char **errorstring)
441 {
442         dpvsimpledecodestream_t *s = (dpvsimpledecodestream_t *)stream;
443         int e;
444         e = s->error;
445         s->error = 0;
446         if (errorstring)
447         {
448                 switch (e)
449                 {
450                         case DPVSIMPLEDECODEERROR_NONE:
451                                 *errorstring = "no error";
452                                 break;
453                         case DPVSIMPLEDECODEERROR_EOF:
454                                 *errorstring = "end of file reached (this is not an error)";
455                                 break;
456                         case DPVSIMPLEDECODEERROR_READERROR:
457                                 *errorstring = "read error (corrupt or incomplete file)";
458                                 break;
459                         case DPVSIMPLEDECODEERROR_SOUNDBUFFERTOOSMALL:
460                                 *errorstring = "sound buffer is too small for decoding frame (please allocate it as large as dpvsimpledecode_getneededsoundbufferlength suggests)";
461                                 break;
462                         case DPVSIMPLEDECODEERROR_INVALIDRMASK:
463                                 *errorstring = "invalid red bits mask";
464                                 break;
465                         case DPVSIMPLEDECODEERROR_INVALIDGMASK:
466                                 *errorstring = "invalid green bits mask";
467                                 break;
468                         case DPVSIMPLEDECODEERROR_INVALIDBMASK:
469                                 *errorstring = "invalid blue bits mask";
470                                 break;
471                         case DPVSIMPLEDECODEERROR_COLORMASKSOVERLAP:
472                                 *errorstring = "color bit masks overlap";
473                                 break;
474                         case DPVSIMPLEDECODEERROR_COLORMASKSEXCEEDBPP:
475                                 *errorstring = "color masks too big for specified bytes per pixel";
476                                 break;
477                         case DPVSIMPLEDECODEERROR_UNSUPPORTEDBPP:
478                                 *errorstring = "unsupported bytes per pixel (must be 2 for 16bit, or 4 for 32bit)";
479                                 break;
480                         default:
481                                 *errorstring = "unknown error";
482                                 break;
483                 }
484         }
485         return e;
486 }
487
488 // returns the width of the image data
489 unsigned int dpvsimpledecode_getwidth(void *stream)
490 {
491         dpvsimpledecodestream_t *s = (dpvsimpledecodestream_t *)stream;
492         return s->info_imagewidth;
493 }
494
495 // returns the height of the image data
496 unsigned int dpvsimpledecode_getheight(void *stream)
497 {
498         dpvsimpledecodestream_t *s = (dpvsimpledecodestream_t *)stream;
499         return s->info_imageheight;
500 }
501
502 // returns the framerate of the stream
503 double dpvsimpledecode_getframerate(void *stream)
504 {
505         dpvsimpledecodestream_t *s = (dpvsimpledecodestream_t *)stream;
506         return s->info_framerate;
507 }
508
509
510
511
512
513 static int dpvsimpledecode_convertpixels(dpvsimpledecodestream_t *s, void *imagedata, int imagebytesperrow)
514 {
515         unsigned int a, x, y, width, height;
516         unsigned int Rloss, Rmask, Rshift, Gloss, Gmask, Gshift, Bloss, Bmask, Bshift;
517         unsigned int *in;
518
519         width = s->info_imagewidth;
520         height = s->info_imageheight;
521
522         Rloss = s->info_imageRloss;
523         Rmask = s->info_imageRmask;
524         Rshift = s->info_imageRshift;
525         Gloss = s->info_imageGloss;
526         Gmask = s->info_imageGmask;
527         Gshift = s->info_imageGshift;
528         Bloss = s->info_imageBloss;
529         Bmask = s->info_imageBmask;
530         Bshift = s->info_imageBshift;
531
532         in = s->videopixels;
533         if (s->info_imagebpp == 4)
534         {
535                 unsigned int *outrow;
536                 for (y = 0;y < height;y++)
537                 {
538                         outrow = (unsigned int *)((unsigned char *)imagedata + y * imagebytesperrow);
539                         for (x = 0;x < width;x++)
540                         {
541                                 a = *in++;
542                                 outrow[x] = (((a >> Rloss) & Rmask) << Rshift) | (((a >> Gloss) & Gmask) << Gshift) | (((a >> Bloss) & Bmask) << Bshift);
543                         }
544                 }
545         }
546         else
547         {
548                 unsigned short *outrow;
549                 for (y = 0;y < height;y++)
550                 {
551                         outrow = (unsigned short *)((unsigned char *)imagedata + y * imagebytesperrow);
552                         if (Rloss == 19 && Gloss == 10 && Bloss == 3 && Rshift == 11 && Gshift == 5 && Bshift == 0)
553                         {
554                                 // optimized
555                                 for (x = 0;x < width;x++)
556                                 {
557                                         a = *in++;
558                                         outrow[x] = ((a >> 8) & 0xF800) | ((a >> 5) & 0x07E0) | ((a >> 3) & 0x001F);
559                                 }
560                         }
561                         else
562                         {
563                                 for (x = 0;x < width;x++)
564                                 {
565                                         a = *in++;
566                                         outrow[x] = (((a >> Rloss) & Rmask) << Rshift) | (((a >> Gloss) & Gmask) << Gshift) | (((a >> Bloss) & Bmask) << Bshift);
567                                 }
568                         }
569                 }
570         }
571         return s->error;
572 }
573
574 static int dpvsimpledecode_decompressimage(dpvsimpledecodestream_t *s)
575 {
576         int i, a, b, colors, g, x1, y1, bw, bh, width, height, palettebits;
577         unsigned int palette[256], *outrow, *out;
578         g = BLOCKSIZE;
579         width = s->info_imagewidth;
580         height = s->info_imageheight;
581         for (y1 = 0;y1 < height;y1 += g)
582         {
583                 outrow = s->videopixels + y1 * width;
584                 bh = g;
585                 if (y1 + bh > height)
586                         bh = height - y1;
587                 for (x1 = 0;x1 < width;x1 += g)
588                 {
589                         out = outrow + x1;
590                         bw = g;
591                         if (x1 + bw > width)
592                                 bw = width - x1;
593                         if (hz_bitstream_read_bit(s->framedatablocks))
594                         {
595                                 // updated block
596                                 palettebits = hz_bitstream_read_bits(s->framedatablocks, 3);
597                                 colors = 1 << palettebits;
598                                 for (i = 0;i < colors;i++)
599                                         palette[i] = hz_bitstream_read_bits(s->framedatablocks, 24);
600                                 if (palettebits)
601                                 {
602                                         for (b = 0;b < bh;b++, out += width)
603                                                 for (a = 0;a < bw;a++)
604                                                         out[a] = palette[hz_bitstream_read_bits(s->framedatablocks, palettebits)];
605                                 }
606                                 else
607                                 {
608                                         for (b = 0;b < bh;b++, out += width)
609                                                 for (a = 0;a < bw;a++)
610                                                         out[a] = palette[0];
611                                 }
612                         }
613                 }
614         }
615         return s->error;
616 }
617
618 // decodes a video frame to the supplied output pixels
619 int dpvsimpledecode_video(void *stream, void *imagedata, unsigned int Rmask, unsigned int Gmask, unsigned int Bmask, unsigned int bytesperpixel, int imagebytesperrow)
620 {
621         dpvsimpledecodestream_t *s = (dpvsimpledecodestream_t *)stream;
622         unsigned int framedatasize;
623         char t[4];
624         s->error = DPVSIMPLEDECODEERROR_NONE;
625         if (dpvsimpledecode_setpixelformat(s, Rmask, Gmask, Bmask, bytesperpixel))
626                 return s->error;
627
628         hz_bitstream_read_blocks_read(s->framedatablocks, s->bitstream, 8);
629         hz_bitstream_read_bytes(s->framedatablocks, t, 4);
630         if (memcmp(t, "VID0", 4))
631         {
632                 if (t[0] == 0)
633                         return (s->error = DPVSIMPLEDECODEERROR_EOF);
634                 else
635                         return (s->error = DPVSIMPLEDECODEERROR_READERROR);
636         }
637         framedatasize = hz_bitstream_read_int(s->framedatablocks);
638         hz_bitstream_read_blocks_read(s->framedatablocks, s->bitstream, framedatasize);
639         if (dpvsimpledecode_decompressimage(s))
640                 return s->error;
641
642         dpvsimpledecode_convertpixels(s, imagedata, imagebytesperrow);
643         return s->error;
644 }