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