]> git.xonotic.org Git - xonotic/darkplaces.git/blob - dpvsimpledecode.c
6cbc44ea93bd7d464c34162ebaf998833e354fd4
[xonotic/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_Open (filename, "rb", false, 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                 break;
283         }
284         for (Rshift = 0;!(Rmask & 1);Rshift++, Rmask >>= 1);
285         for (Gshift = 0;!(Gmask & 1);Gshift++, Gmask >>= 1);
286         for (Bshift = 0;!(Bmask & 1);Bshift++, Bmask >>= 1);
287         if (((Rmask + 1) & Rmask) != 0)
288         {
289                 s->error = DPVSIMPLEDECODEERROR_INVALIDRMASK;
290                 return s->error;
291         }
292         if (((Gmask + 1) & Gmask) != 0)
293         {
294                 s->error = DPVSIMPLEDECODEERROR_INVALIDGMASK;
295                 return s->error;
296         }
297         if (((Bmask + 1) & Bmask) != 0)
298         {
299                 s->error = DPVSIMPLEDECODEERROR_INVALIDBMASK;
300                 return s->error;
301         }
302         for (Rbits = 0;Rmask & 1;Rbits++, Rmask >>= 1);
303         for (Gbits = 0;Gmask & 1;Gbits++, Gmask >>= 1);
304         for (Bbits = 0;Bmask & 1;Bbits++, Bmask >>= 1);
305         if (Rbits > 8)
306         {
307                 Rshift += (Rbits - 8);
308                 Rbits = 8;
309         }
310         if (Gbits > 8)
311         {
312                 Gshift += (Gbits - 8);
313                 Gbits = 8;
314         }
315         if (Bbits > 8)
316         {
317                 Bshift += (Bbits - 8);
318                 Bbits = 8;
319         }
320         s->info_imagebpp = bytesperpixel;
321         s->info_imageRloss = 16 + (8 - Rbits);
322         s->info_imageGloss =  8 + (8 - Gbits);
323         s->info_imageBloss =  0 + (8 - Bbits);
324         s->info_imageRmask = (1 << Rbits) - 1;
325         s->info_imageGmask = (1 << Gbits) - 1;
326         s->info_imageBmask = (1 << Bbits) - 1;
327         s->info_imageRshift = Rshift;
328         s->info_imageGshift = Gshift;
329         s->info_imageBshift = Bshift;
330         s->info_imagesize = s->info_imagewidth * s->info_imageheight * s->info_imagebpp;
331         return s->error;
332 }
333
334 // opening and closing streams
335
336 // opens a stream
337 void *dpvsimpledecode_open(char *filename, char **errorstring)
338 {
339         dpvsimpledecodestream_t *s;
340         char t[8], *wavename;
341         if (errorstring != NULL)
342                 *errorstring = NULL;
343         s = (dpvsimpledecodestream_t *)Z_Malloc(sizeof(dpvsimpledecodestream_t));
344         if (s != NULL)
345         {
346                 s->bitstream = hz_bitstream_read_open(filename);
347                 if (s->bitstream != NULL)
348                 {
349                         // check file identification
350                         s->framedatablocks = hz_bitstream_read_blocks_new();
351                         if (s->framedatablocks != NULL)
352                         {
353                                 hz_bitstream_read_blocks_read(s->framedatablocks, s->bitstream, 8);
354                                 hz_bitstream_read_bytes(s->framedatablocks, t, 8);
355                                 if (!memcmp(t, "DPVideo", 8))
356                                 {
357                                         // check version number
358                                         hz_bitstream_read_blocks_read(s->framedatablocks, s->bitstream, 2);
359                                         if (hz_bitstream_read_short(s->framedatablocks) == 1)
360                                         {
361                                                 hz_bitstream_read_blocks_read(s->framedatablocks, s->bitstream, 12);
362                                                 s->info_imagewidth = hz_bitstream_read_short(s->framedatablocks);
363                                                 s->info_imageheight = hz_bitstream_read_short(s->framedatablocks);
364                                                 s->info_framerate = (double) hz_bitstream_read_int(s->framedatablocks) * (1.0 / 65536.0);
365
366                                                 if (s->info_framerate > 0.0)
367                                                 {
368                                                         s->videopixels = (unsigned int *)Z_Malloc(s->info_imagewidth * s->info_imageheight * sizeof(*s->videopixels));
369                                                         if (s->videopixels != NULL)
370                                                         {
371                                                                 size_t namelen;
372
373                                                                 namelen = strlen(filename) + 10;
374                                                                 wavename = (char *)Z_Malloc(namelen);
375                                                                 if (wavename)
376                                                                 {
377                                                                         sfx_t* sfx;
378
379                                                                         FS_StripExtension(filename, wavename, namelen);
380                                                                         strlcat(wavename, ".wav", namelen);
381                                                                         sfx = S_PrecacheSound (wavename, false, false);
382                                                                         if (sfx != NULL)
383                                                                                 s->sndchan = S_StartSound (-1, 0, sfx, vec3_origin, 1.0f, 0);
384                                                                         else
385                                                                                 s->sndchan = -1;
386                                                                         Z_Free(wavename);
387                                                                 }
388                                                                 // all is well...
389                                                                 s->videoframenum = -10000;
390                                                                 return s;
391                                                         }
392                                                         else if (errorstring != NULL)
393                                                                 *errorstring = "unable to allocate video image buffer";
394                                                 }
395                                                 else if (errorstring != NULL)
396                                                         *errorstring = "error in video info chunk";
397                                         }
398                                         else if (errorstring != NULL)
399                                                 *errorstring = "read error";
400                                 }
401                                 else if (errorstring != NULL)
402                                         *errorstring = "not a dpvideo file";
403                                 hz_bitstream_read_blocks_free(s->framedatablocks);
404                         }
405                         else if (errorstring != NULL)
406                                 *errorstring = "unable to allocate memory for reading buffer";
407                         hz_bitstream_read_close(s->bitstream);
408                 }
409                 else if (errorstring != NULL)
410                         *errorstring = "unable to open file";
411                 Z_Free(s);
412         }
413         else if (errorstring != NULL)
414                 *errorstring = "unable to allocate memory for stream info structure";
415         return NULL;
416 }
417
418 // closes a stream
419 void dpvsimpledecode_close(void *stream)
420 {
421         dpvsimpledecodestream_t *s = (dpvsimpledecodestream_t *)stream;
422         if (s == NULL)
423                 return;
424         if (s->videopixels)
425                 Z_Free(s->videopixels);
426         if (s->sndchan != -1)
427                 S_StopChannel (s->sndchan, true);
428         if (s->framedatablocks)
429                 hz_bitstream_read_blocks_free(s->framedatablocks);
430         if (s->bitstream)
431                 hz_bitstream_read_close(s->bitstream);
432         Z_Free(s);
433 }
434
435 // utilitarian functions
436
437 // returns the current error number for the stream, and resets the error
438 // number to DPVSIMPLEDECODEERROR_NONE
439 // if the supplied string pointer variable is not NULL, it will be set to the
440 // error message
441 int dpvsimpledecode_error(void *stream, char **errorstring)
442 {
443         dpvsimpledecodestream_t *s = (dpvsimpledecodestream_t *)stream;
444         int e;
445         e = s->error;
446         s->error = 0;
447         if (errorstring)
448         {
449                 switch (e)
450                 {
451                         case DPVSIMPLEDECODEERROR_NONE:
452                                 *errorstring = "no error";
453                                 break;
454                         case DPVSIMPLEDECODEERROR_EOF:
455                                 *errorstring = "end of file reached (this is not an error)";
456                                 break;
457                         case DPVSIMPLEDECODEERROR_READERROR:
458                                 *errorstring = "read error (corrupt or incomplete file)";
459                                 break;
460                         case DPVSIMPLEDECODEERROR_SOUNDBUFFERTOOSMALL:
461                                 *errorstring = "sound buffer is too small for decoding frame (please allocate it as large as dpvsimpledecode_getneededsoundbufferlength suggests)";
462                                 break;
463                         case DPVSIMPLEDECODEERROR_INVALIDRMASK:
464                                 *errorstring = "invalid red bits mask";
465                                 break;
466                         case DPVSIMPLEDECODEERROR_INVALIDGMASK:
467                                 *errorstring = "invalid green bits mask";
468                                 break;
469                         case DPVSIMPLEDECODEERROR_INVALIDBMASK:
470                                 *errorstring = "invalid blue bits mask";
471                                 break;
472                         case DPVSIMPLEDECODEERROR_COLORMASKSOVERLAP:
473                                 *errorstring = "color bit masks overlap";
474                                 break;
475                         case DPVSIMPLEDECODEERROR_COLORMASKSEXCEEDBPP:
476                                 *errorstring = "color masks too big for specified bytes per pixel";
477                                 break;
478                         case DPVSIMPLEDECODEERROR_UNSUPPORTEDBPP:
479                                 *errorstring = "unsupported bytes per pixel (must be 2 for 16bit, or 4 for 32bit)";
480                                 break;
481                         default:
482                                 *errorstring = "unknown error";
483                                 break;
484                 }
485         }
486         return e;
487 }
488
489 // returns the width of the image data
490 unsigned int dpvsimpledecode_getwidth(void *stream)
491 {
492         dpvsimpledecodestream_t *s = (dpvsimpledecodestream_t *)stream;
493         return s->info_imagewidth;
494 }
495
496 // returns the height of the image data
497 unsigned int dpvsimpledecode_getheight(void *stream)
498 {
499         dpvsimpledecodestream_t *s = (dpvsimpledecodestream_t *)stream;
500         return s->info_imageheight;
501 }
502
503 // returns the framerate of the stream
504 double dpvsimpledecode_getframerate(void *stream)
505 {
506         dpvsimpledecodestream_t *s = (dpvsimpledecodestream_t *)stream;
507         return s->info_framerate;
508 }
509
510
511
512
513
514 static int dpvsimpledecode_convertpixels(dpvsimpledecodestream_t *s, void *imagedata, int imagebytesperrow)
515 {
516         unsigned int a, x, y, width, height;
517         unsigned int Rloss, Rmask, Rshift, Gloss, Gmask, Gshift, Bloss, Bmask, Bshift;
518         unsigned int *in;
519
520         width = s->info_imagewidth;
521         height = s->info_imageheight;
522
523         Rloss = s->info_imageRloss;
524         Rmask = s->info_imageRmask;
525         Rshift = s->info_imageRshift;
526         Gloss = s->info_imageGloss;
527         Gmask = s->info_imageGmask;
528         Gshift = s->info_imageGshift;
529         Bloss = s->info_imageBloss;
530         Bmask = s->info_imageBmask;
531         Bshift = s->info_imageBshift;
532
533         in = s->videopixels;
534         if (s->info_imagebpp == 4)
535         {
536                 unsigned int *outrow;
537                 for (y = 0;y < height;y++)
538                 {
539                         outrow = (unsigned int *)((unsigned char *)imagedata + y * imagebytesperrow);
540                         for (x = 0;x < width;x++)
541                         {
542                                 a = *in++;
543                                 outrow[x] = (((a >> Rloss) & Rmask) << Rshift) | (((a >> Gloss) & Gmask) << Gshift) | (((a >> Bloss) & Bmask) << Bshift);
544                         }
545                 }
546         }
547         else
548         {
549                 unsigned short *outrow;
550                 for (y = 0;y < height;y++)
551                 {
552                         outrow = (unsigned short *)((unsigned char *)imagedata + y * imagebytesperrow);
553                         if (Rloss == 19 && Gloss == 10 && Bloss == 3 && Rshift == 11 && Gshift == 5 && Bshift == 0)
554                         {
555                                 // optimized
556                                 for (x = 0;x < width;x++)
557                                 {
558                                         a = *in++;
559                                         outrow[x] = ((a >> 8) & 0xF800) | ((a >> 5) & 0x07E0) | ((a >> 3) & 0x001F);
560                                 }
561                         }
562                         else
563                         {
564                                 for (x = 0;x < width;x++)
565                                 {
566                                         a = *in++;
567                                         outrow[x] = (((a >> Rloss) & Rmask) << Rshift) | (((a >> Gloss) & Gmask) << Gshift) | (((a >> Bloss) & Bmask) << Bshift);
568                                 }
569                         }
570                 }
571         }
572         return s->error;
573 }
574
575 static int dpvsimpledecode_decompressimage(dpvsimpledecodestream_t *s)
576 {
577         int i, a, b, colors, g, x1, y1, bw, bh, width, height, palettebits;
578         unsigned int palette[256], *outrow, *out;
579         g = BLOCKSIZE;
580         width = s->info_imagewidth;
581         height = s->info_imageheight;
582         for (y1 = 0;y1 < height;y1 += g)
583         {
584                 outrow = s->videopixels + y1 * width;
585                 bh = g;
586                 if (y1 + bh > height)
587                         bh = height - y1;
588                 for (x1 = 0;x1 < width;x1 += g)
589                 {
590                         out = outrow + x1;
591                         bw = g;
592                         if (x1 + bw > width)
593                                 bw = width - x1;
594                         if (hz_bitstream_read_bit(s->framedatablocks))
595                         {
596                                 // updated block
597                                 palettebits = hz_bitstream_read_bits(s->framedatablocks, 3);
598                                 colors = 1 << palettebits;
599                                 for (i = 0;i < colors;i++)
600                                         palette[i] = hz_bitstream_read_bits(s->framedatablocks, 24);
601                                 if (palettebits)
602                                 {
603                                         for (b = 0;b < bh;b++, out += width)
604                                                 for (a = 0;a < bw;a++)
605                                                         out[a] = palette[hz_bitstream_read_bits(s->framedatablocks, palettebits)];
606                                 }
607                                 else
608                                 {
609                                         for (b = 0;b < bh;b++, out += width)
610                                                 for (a = 0;a < bw;a++)
611                                                         out[a] = palette[0];
612                                 }
613                         }
614                 }
615         }
616         return s->error;
617 }
618
619 // decodes a video frame to the supplied output pixels
620 int dpvsimpledecode_video(void *stream, void *imagedata, unsigned int Rmask, unsigned int Gmask, unsigned int Bmask, unsigned int bytesperpixel, int imagebytesperrow)
621 {
622         dpvsimpledecodestream_t *s = (dpvsimpledecodestream_t *)stream;
623         unsigned int framedatasize;
624         char t[4];
625         s->error = DPVSIMPLEDECODEERROR_NONE;
626         if (dpvsimpledecode_setpixelformat(s, Rmask, Gmask, Bmask, bytesperpixel))
627                 return s->error;
628
629         hz_bitstream_read_blocks_read(s->framedatablocks, s->bitstream, 8);
630         hz_bitstream_read_bytes(s->framedatablocks, t, 4);
631         if (memcmp(t, "VID0", 4))
632         {
633                 if (t[0] == 0)
634                         return (s->error = DPVSIMPLEDECODEERROR_EOF);
635                 else
636                         return (s->error = DPVSIMPLEDECODEERROR_READERROR);
637         }
638         framedatasize = hz_bitstream_read_int(s->framedatablocks);
639         hz_bitstream_read_blocks_read(s->framedatablocks, s->bitstream, framedatasize);
640         if (dpvsimpledecode_decompressimage(s))
641                 return s->error;
642
643         dpvsimpledecode_convertpixels(s, imagedata, imagebytesperrow);
644         return s->error;
645 }