initial Interplay video decoder
[ffmpeg.git] / libavcodec / interplayvideo.c
1 /*
2  * Interplay MVE Video Decoder
3  * Copyright (C) 2003 the ffmpeg project
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  */
20
21 /**
22  * @file interplayvideo.c
23  * Interplay MVE Video Decoder by Mike Melanson (melanson@pcisys.net)
24  * For more information about the Interplay MVE format, visit:
25  *   http://www.pcisys.net/~melanson/codecs/interplay-mve.txt
26  * This code is written in such a way that the identifiers match up
27  * with the encoding descriptions in the document.
28  *
29  * This decoder presently only supports a PAL8 output colorspace.
30  *
31  * An Interplay video frame consists of 2 parts: The decoding map and
32  * the video data. A demuxer must load these 2 parts together in a single
33  * buffer before sending it through the stream to this decoder.
34  */
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40
41 #include "common.h"
42 #include "avcodec.h"
43 #include "dsputil.h"
44
45 #define PALETTE_COUNT 256
46
47 /* debugging support */
48 #define DEBUG_INTERPLAY 0
49 #if DEBUG_INTERPLAY
50 #define debug_interplay printf
51 #else
52 static inline void debug_interplay(const char *format, ...) { }
53 #endif
54
55 typedef struct IpvideoContext {
56
57     AVCodecContext *avctx;
58     DSPContext dsp;
59     AVFrame last_frame;
60     AVFrame current_frame;
61     int first_frame;
62     unsigned char *decoding_map;
63     int decoding_map_size;
64
65     unsigned char *buf;
66     int size;
67
68     unsigned char palette[PALETTE_COUNT * 4];
69
70 } IpvideoContext;
71
72 #define CHECK_STREAM_PTR(n) \
73   if ((sg_stream_ptr + n) > sg_stream_end) { \
74     printf ("Interplay video warning: stream_ptr out of bounds (%p >= %p)\n", \
75       sg_stream_ptr + n, sg_stream_end); \
76     return -1; \
77   }
78
79 static void ipvideo_new_palette(IpvideoContext *s, unsigned char *palette) {
80
81     int i;
82     unsigned char r, g, b;
83     unsigned int *palette32;
84
85     switch (s->avctx->pix_fmt) {
86
87     case PIX_FMT_PAL8:
88         palette32 = (unsigned int *)s->palette;
89         for (i = 0; i < PALETTE_COUNT; i++) {
90             r = *palette++;
91             g = *palette++;
92             b = *palette++;
93             palette32[i] = (r << 16) | (g << 8) | (b);
94         }
95         break;
96
97     default:
98         printf ("Interplay video: Unhandled video format\n");
99         break;
100     }
101 }
102
103 static unsigned char *sg_stream_ptr;
104 static unsigned char *sg_stream_end;
105 static unsigned char *sg_current_plane;
106 static unsigned char *sg_output_plane;
107 static unsigned char *sg_last_plane;
108 static int sg_line_inc;
109 static int sg_stride;
110 static int sg_upper_motion_limit_offset;
111 static DSPContext sg_dsp;
112
113 static int ipvideo_decode_block_opcode_0x0_0x1(void)
114 {
115     int x, y;
116     unsigned char *src_block;
117
118     /* skip block, which actually means to copy from previous frame */
119     src_block = sg_last_plane + (sg_output_plane - sg_current_plane);
120     for (y = 0; y < 8; y++) {
121         for (x = 0; x < 8; x++) {
122             *sg_output_plane++ = *src_block++;
123         }
124         sg_output_plane += sg_line_inc;
125         src_block += sg_line_inc;
126     }
127
128     /* report success */
129     return 0;
130 }
131
132 #define COPY_FROM_CURRENT() \
133     motion_offset = current_offset; \
134     motion_offset += y * sg_stride; \
135     motion_offset += x; \
136     if (motion_offset < 0) { \
137         printf (" Interplay video: motion offset < 0 (%d)\n", motion_offset); \
138         return -1; \
139     } else if (motion_offset > sg_upper_motion_limit_offset) { \
140         printf (" Interplay video: motion offset above limit (%d >= %d)\n", \
141             motion_offset, sg_upper_motion_limit_offset); \
142         return -1; \
143     } \
144     sg_dsp.put_pixels_tab[0][0](sg_output_plane, \
145         sg_current_plane + motion_offset, sg_stride, 8);
146
147 #define COPY_FROM_PREVIOUS() \
148     motion_offset = current_offset; \
149     motion_offset += y * sg_stride; \
150     motion_offset += x; \
151     if (motion_offset < 0) { \
152         printf (" Interplay video: motion offset < 0 (%d)\n", motion_offset); \
153         return -1; \
154     } else if (motion_offset > sg_upper_motion_limit_offset) { \
155         printf (" Interplay video: motion offset above limit (%d >= %d)\n", \
156             motion_offset, sg_upper_motion_limit_offset); \
157         return -1; \
158     } \
159     sg_dsp.put_pixels_tab[0][0](sg_output_plane, \
160         sg_last_plane + motion_offset, sg_stride, 8);
161
162 static int ipvideo_decode_block_opcode_0x2(void)
163 {
164     unsigned char B;
165     int x, y;
166     int motion_offset;
167     int current_offset = sg_output_plane - sg_current_plane;
168
169     /* This is the opcode which claims to copy data from within the same
170      * frame at a coordinate which has not been rendered yet. Assume that
171      * it is supposed to be copied from the previous frame. */
172
173     /* need 1 more byte for motion */
174     CHECK_STREAM_PTR(1);
175     B = *sg_stream_ptr++;
176
177     if (B < 56) {
178         x = 8 + (B % 7);
179         y = B / 7;
180     } else {
181         x = -14 + ((B - 56) % 29);
182         y =   8 + ((B - 56) / 29);
183     }
184
185     debug_interplay ("    motion byte = %d, (x, y) = (%d, %d)\n", B, x, y);
186     COPY_FROM_PREVIOUS();
187
188     /* report success */
189     return 0;
190 }
191
192 static int ipvideo_decode_block_opcode_0x3(void)
193 {
194     unsigned char B;
195     int x, y;
196     int motion_offset;
197     int current_offset = sg_output_plane - sg_current_plane;
198
199     /* copy 8x8 block from current frame from an up/left block */
200
201     /* need 1 more byte for motion */
202     CHECK_STREAM_PTR(1);
203     B = *sg_stream_ptr++;
204
205     if (B < 56) {
206         x = -(8 + (B % 7));
207         y = -(B / 7);
208     } else {
209         x = -(-14 + ((B - 56) % 29));
210         y = -(  8 + ((B - 56) / 29));
211     }
212
213     debug_interplay ("    motion byte = %d, (x, y) = (%d, %d)\n", B, x, y);
214     COPY_FROM_CURRENT();
215
216     /* report success */
217     return 0;
218 }
219
220 static int ipvideo_decode_block_opcode_0x4(void)
221 {
222     int x, y;
223     unsigned char B, BL, BH;
224     int motion_offset;
225     int current_offset = sg_output_plane - sg_current_plane;
226
227     /* copy a block from the previous frame; need 1 more byte */
228     CHECK_STREAM_PTR(1);
229
230     B = *sg_stream_ptr++;
231     BL = B & 0x0F;
232     BH = (B >> 4) & 0x0F;
233     x = -8 + BL;
234     y = -8 + BH;
235
236     debug_interplay ("    motion byte = %d, (x, y) = (%d, %d)\n", B, x, y);
237     COPY_FROM_PREVIOUS();
238
239     /* report success */
240     return 0;
241 }
242
243 static int ipvideo_decode_block_opcode_0x5(void)
244 {
245     signed char x, y;
246     int motion_offset;
247     int current_offset = sg_output_plane - sg_current_plane;
248
249     /* copy a block from the previous frame using an expanded range;
250      * need 2 more bytes */
251     CHECK_STREAM_PTR(2);
252
253     x = *sg_stream_ptr++;
254     y = *sg_stream_ptr++;
255
256     debug_interplay ("    motion bytes = %d, %d\n", x, y);
257     COPY_FROM_PREVIOUS();
258
259     /* report success */
260     return 0;
261 }
262
263 static int ipvideo_decode_block_opcode_0x6(void)
264 {
265     /* mystery opcode? skip multiple blocks? */
266     printf ("  Interplay video: Help! Mystery opcode 0x6 seen\n");
267
268     /* report success */
269     return 0;
270 }
271
272 static int ipvideo_decode_block_opcode_0x7(void)
273 {
274     int x, y;
275     unsigned char P0, P1;
276     unsigned char B[8];
277     unsigned int flags;
278     int bitmask;
279
280     /* 2-color encoding */
281     CHECK_STREAM_PTR(2);
282
283     P0 = *sg_stream_ptr++;
284     P1 = *sg_stream_ptr++;
285
286     if (P0 <= P1) {
287
288         /* need 8 more bytes from the stream */
289         CHECK_STREAM_PTR(8);
290         for (y = 0; y < 8; y++)
291             B[y] = *sg_stream_ptr++;
292
293         for (y = 0; y < 8; y++) {
294             flags = B[y];
295             for (x = 0x80; x != 0; x >>= 1) {
296                 if (flags & x)
297                     *sg_output_plane++ = P1;
298                 else
299                     *sg_output_plane++ = P0;
300             }
301             sg_output_plane += sg_line_inc;
302         }
303
304     } else {
305
306         /* need 2 more bytes from the stream */
307         CHECK_STREAM_PTR(2);
308         B[0] = *sg_stream_ptr++;
309         B[1] = *sg_stream_ptr++;
310
311         flags = (B[0] << 8) | B[1];
312         bitmask = 0x8000;
313         for (y = 0; y < 8; y += 2) {
314             for (x = 0; x < 8; x += 2, bitmask >>= 1) {
315                 if (flags & bitmask) {
316                     *(sg_output_plane + x) = P0;
317                     *(sg_output_plane + x + 1) = P0;
318                     *(sg_output_plane + sg_stride + x) = P0;
319                     *(sg_output_plane + sg_stride + x + 1) = P0;
320                 } else {
321                     *(sg_output_plane + x) = P1;
322                     *(sg_output_plane + x + 1) = P1;
323                     *(sg_output_plane + sg_stride + x) = P1;
324                     *(sg_output_plane + sg_stride + x + 1) = P1;
325                 }
326             }
327             sg_output_plane += sg_stride * 2;
328         }
329     }
330
331     /* report success */
332     return 0;
333 }
334
335 static int ipvideo_decode_block_opcode_0x8(void)
336 {
337     int x, y;
338     unsigned char P[8];
339     unsigned char B[8];
340     unsigned int flags = 0;
341     unsigned int bitmask = 0;
342     unsigned char P0 = 0, P1 = 0;
343     int lower_half = 0;
344
345     /* 2-color encoding for each 4x4 quadrant, or 2-color encoding on
346      * either top and bottom or left and right halves */
347     CHECK_STREAM_PTR(2);
348
349     P[0] = *sg_stream_ptr++;
350     P[1] = *sg_stream_ptr++;
351
352     if (P[0] <= P[1]) {
353
354         /* need 12 more bytes */
355         CHECK_STREAM_PTR(12);
356         B[0] = *sg_stream_ptr++;  B[1] = *sg_stream_ptr++;
357         P[2] = *sg_stream_ptr++;  P[3] = *sg_stream_ptr++;
358         B[2] = *sg_stream_ptr++;  B[3] = *sg_stream_ptr++;
359         P[4] = *sg_stream_ptr++;  P[5] = *sg_stream_ptr++;
360         B[4] = *sg_stream_ptr++;  B[5] = *sg_stream_ptr++;
361         P[6] = *sg_stream_ptr++;  P[7] = *sg_stream_ptr++;
362         B[6] = *sg_stream_ptr++;  B[7] = *sg_stream_ptr++;
363
364         for (y = 0; y < 8; y++) {
365
366             /* time to reload flags? */
367             if (y == 0) {
368                 flags =
369                     ((B[0] & 0xF0) << 24) | ((B[4] & 0xF0) << 20) |
370                     ((B[0] & 0x0F) << 20) | ((B[4] & 0x0F) << 16) |
371                     ((B[1] & 0xF0) <<  8) | ((B[5] & 0xF0) <<  4) |
372                     ((B[1] & 0x0F) <<  4) | ((B[5] & 0x0F) <<  0);
373                 bitmask = 0x80000000;
374                 lower_half = 0;  /* still on top half */
375             } else if (y == 4) {
376                 flags =
377                     ((B[2] & 0xF0) << 24) | ((B[6] & 0xF0) << 20) |
378                     ((B[2] & 0x0F) << 20) | ((B[6] & 0x0F) << 16) |
379                     ((B[3] & 0xF0) <<  8) | ((B[7] & 0xF0) <<  4) |
380                     ((B[3] & 0x0F) <<  4) | ((B[7] & 0x0F) <<  0);
381                 bitmask = 0x80000000;
382                 lower_half = 4;
383             }
384
385             for (x = 0; x < 8; x++, bitmask >>= 1) {
386                 /* get the pixel values ready for this quadrant */
387                 if (x == 0) {
388                     P0 = P[lower_half + 0];
389                     P1 = P[lower_half + 1];
390                 } else if (x == 4) {
391                     P0 = P[lower_half + 2];
392                     P1 = P[lower_half + 3];
393                 }
394
395                 if (flags & bitmask)
396                     *sg_output_plane++ = P1;
397                 else
398                     *sg_output_plane++ = P0;
399             }
400             sg_output_plane += sg_line_inc;
401         }
402
403     } else {
404
405         /* need 10 more bytes */
406         CHECK_STREAM_PTR(10);
407         B[0] = *sg_stream_ptr++;  B[1] = *sg_stream_ptr++;
408         B[2] = *sg_stream_ptr++;  B[3] = *sg_stream_ptr++;
409         P[2] = *sg_stream_ptr++;  P[3] = *sg_stream_ptr++;
410         B[4] = *sg_stream_ptr++;  B[5] = *sg_stream_ptr++;
411         B[6] = *sg_stream_ptr++;  B[7] = *sg_stream_ptr++;
412
413         if (P[2] <= P[3]) {
414
415             /* vertical split; left & right halves are 2-color encoded */
416
417             for (y = 0; y < 8; y++) {
418
419                 /* time to reload flags? */
420                 if (y == 0) {
421                     flags =
422                         ((B[0] & 0xF0) << 24) | ((B[4] & 0xF0) << 20) |
423                         ((B[0] & 0x0F) << 20) | ((B[4] & 0x0F) << 16) |
424                         ((B[1] & 0xF0) <<  8) | ((B[5] & 0xF0) <<  4) |
425                         ((B[1] & 0x0F) <<  4) | ((B[5] & 0x0F) <<  0);
426                     bitmask = 0x80000000;
427                 } else if (y == 4) {
428                     flags =
429                         ((B[2] & 0xF0) << 24) | ((B[6] & 0xF0) << 20) |
430                         ((B[2] & 0x0F) << 20) | ((B[6] & 0x0F) << 16) |
431                         ((B[3] & 0xF0) <<  8) | ((B[7] & 0xF0) <<  4) |
432                         ((B[3] & 0x0F) <<  4) | ((B[7] & 0x0F) <<  0);
433                     bitmask = 0x80000000;
434                 }
435
436                 for (x = 0; x < 8; x++, bitmask >>= 1) {
437                     /* get the pixel values ready for this half */
438                     if (x == 0) {
439                         P0 = P[0];
440                         P1 = P[1];
441                     } else if (x == 4) {
442                         P0 = P[2];
443                         P1 = P[3];
444                     }
445
446                     if (flags & bitmask)
447                         *sg_output_plane++ = P0;
448                     else
449                         *sg_output_plane++ = P1;
450                 }
451                 sg_output_plane += sg_line_inc;
452             }
453
454         } else {
455
456             /* horizontal split; top & bottom halves are 2-color encoded */
457
458             for (y = 0; y < 8; y++) {
459
460                 flags = B[y];
461                 if (y == 0) {
462                     P0 = P[0];
463                     P1 = P[1];
464                 } else if (y == 4) {
465                     P0 = P[2];
466                     P1 = P[3];
467                 }
468
469                 for (bitmask = 0x80; bitmask != 0; bitmask >>= 1) {
470
471                     if (flags & bitmask)
472                         *sg_output_plane++ = P0;
473                     else
474                         *sg_output_plane++ = P1;
475                 }
476                 sg_output_plane += sg_line_inc;
477             }
478         }
479     }
480
481     /* report success */
482     return 0;
483 }
484
485 static int ipvideo_decode_block_opcode_0x9(void)
486 {
487     int x, y;
488     unsigned char P[4];
489     unsigned int flags = 0;
490     int shifter = 0;
491     unsigned char pix;
492
493     /* 4-color encoding */
494     CHECK_STREAM_PTR(4);
495
496     for (y = 0; y < 4; y++)
497         P[y] = *sg_stream_ptr++;
498
499     if ((P[0] <= P[1]) && (P[2] <= P[3])) {
500
501         /* 1 of 4 colors for each pixel, need 16 more bytes */
502         CHECK_STREAM_PTR(16);
503
504         for (y = 0; y < 8; y++) {
505             /* get the next set of 8 2-bit flags */
506             flags = (sg_stream_ptr[0] << 8) | sg_stream_ptr[1];
507             sg_stream_ptr += 2;
508             for (x = 0, shifter = 14; x < 8; x++, shifter -= 2) {
509                 *sg_output_plane++ = P[(flags >> shifter) & 0x03];
510             }
511             sg_output_plane += sg_line_inc;
512         }
513
514     } else if ((P[0] <= P[1]) && (P[2] > P[3])) {
515
516         /* 1 of 4 colors for each 2x2 block, need 4 more bytes */
517         CHECK_STREAM_PTR(4);
518
519         flags = 0;
520         flags = (flags << 8) | *sg_stream_ptr++;
521         flags = (flags << 8) | *sg_stream_ptr++;
522         flags = (flags << 8) | *sg_stream_ptr++;
523         flags = (flags << 8) | *sg_stream_ptr++;
524         shifter = 30;
525
526         for (y = 0; y < 8; y += 2) {
527             for (x = 0; x < 8; x += 2, shifter -= 2) {
528                 pix = P[(flags >> shifter) & 0x03];
529                 *(sg_output_plane + x) = pix;
530                 *(sg_output_plane + x + 1) = pix;
531                 *(sg_output_plane + sg_stride + x) = pix;
532                 *(sg_output_plane + sg_stride + x + 1) = pix;
533             }
534             sg_output_plane += sg_stride * 2;
535         }
536
537     } else if ((P[0] > P[1]) && (P[2] <= P[3])) {
538
539         /* 1 of 4 colors for each 2x1 block, need 8 more bytes */
540         CHECK_STREAM_PTR(8);
541
542         for (y = 0; y < 8; y++) {
543             /* time to reload flags? */
544             if ((y == 0) || (y == 4)) {
545                 flags = 0;
546                 flags = (flags << 8) | *sg_stream_ptr++;
547                 flags = (flags << 8) | *sg_stream_ptr++;
548                 flags = (flags << 8) | *sg_stream_ptr++;
549                 flags = (flags << 8) | *sg_stream_ptr++;
550                 shifter = 30;
551             }
552             for (x = 0; x < 8; x += 2, shifter -= 2) {
553                 pix = P[(flags >> shifter) & 0x03];
554                 *(sg_output_plane + x) = pix;
555                 *(sg_output_plane + x + 1) = pix;
556             }
557             sg_output_plane += sg_stride;
558         }
559
560     } else {
561
562         /* 1 of 4 colors for each 1x2 block, need 8 more bytes */
563         CHECK_STREAM_PTR(8);
564
565         for (y = 0; y < 8; y += 2) {
566             /* time to reload flags? */
567             if ((y == 0) || (y == 4)) {
568                 flags = 0;
569                 flags = (flags << 8) | *sg_stream_ptr++;
570                 flags = (flags << 8) | *sg_stream_ptr++;
571                 flags = (flags << 8) | *sg_stream_ptr++;
572                 flags = (flags << 8) | *sg_stream_ptr++;
573                 shifter = 30;
574             }
575             for (x = 0; x < 8; x++, shifter -= 2) {
576                 pix = P[(flags >> shifter) & 0x03];
577                 *(sg_output_plane + x) = pix;
578                 *(sg_output_plane + sg_stride + x) = pix;
579             }
580             sg_output_plane += sg_stride * 2;
581         }
582     }
583
584     /* report success */
585     return 0;
586 }
587
588 static int ipvideo_decode_block_opcode_0xA(void)
589 {
590     int x, y;
591     unsigned char P[16];
592     unsigned char B[16];
593     int flags = 0;
594     int shifter = 0;
595     int index;
596     int split;
597     int lower_half;
598
599     /* 4-color encoding for each 4x4 quadrant, or 4-color encoding on
600      * either top and bottom or left and right halves */
601     CHECK_STREAM_PTR(4);
602
603     for (y = 0; y < 4; y++)
604         P[y] = *sg_stream_ptr++;
605
606     if (P[0] <= P[1]) {
607
608         /* 4-color encoding for each quadrant; need 28 more bytes */
609         CHECK_STREAM_PTR(28);
610
611         for (y = 0; y < 4; y++)
612             B[y] = *sg_stream_ptr++;
613         for (y = 4; y < 16; y += 4) {
614             for (x = y; x < y + 4; x++)
615                 P[x] = *sg_stream_ptr++;
616             for (x = y; x < y + 4; x++)
617                 B[x] = *sg_stream_ptr++;
618         }
619
620         for (y = 0; y < 8; y++) {
621
622             lower_half = (y >= 4) ? 4 : 0;
623             flags = (B[y] << 8) | B[y + 8];
624
625             for (x = 0, shifter = 14; x < 8; x++, shifter -= 2) {
626                 split = (x >= 4) ? 8 : 0;
627                 index = split + lower_half + ((flags >> shifter) & 0x03);
628                 *sg_output_plane++ = P[index];
629             }
630
631             sg_output_plane += sg_line_inc;
632         }
633
634     } else {
635
636         /* 4-color encoding for either left and right or top and bottom
637          * halves; need 20 more bytes */
638         CHECK_STREAM_PTR(20);
639
640         for (y = 0; y < 8; y++)
641             B[y] = *sg_stream_ptr++;
642         for (y = 4; y < 8; y++)
643             P[y] = *sg_stream_ptr++;
644         for (y = 8; y < 16; y++)
645             B[y] = *sg_stream_ptr++;
646
647         if (P[4] <= P[5]) {
648
649             /* block is divided into left and right halves */
650             for (y = 0; y < 8; y++) {
651
652                 flags = (B[y] << 8) | B[y + 8];
653                 split = 0;
654
655                 for (x = 0, shifter = 14; x < 8; x++, shifter -= 2) {
656                     if (x == 4)
657                         split = 4;
658                     *sg_output_plane++ = P[split + ((flags >> shifter) & 0x03)];
659                 }
660
661                 sg_output_plane += sg_line_inc;
662             }
663
664         } else {
665
666             /* block is divided into top and bottom halves */
667             split = 0;
668             for (y = 0; y < 8; y++) {
669
670                 flags = (B[y * 2] << 8) | B[y * 2 + 1];
671                 if (y == 4)
672                     split = 4;
673
674                 for (x = 0, shifter = 14; x < 8; x++, shifter -= 2)
675                     *sg_output_plane++ = P[split + ((flags >> shifter) & 0x03)];
676
677                 sg_output_plane += sg_line_inc;
678             }
679         }
680     }
681
682     /* report success */
683     return 0;
684 }
685
686 static int ipvideo_decode_block_opcode_0xB(void)
687 {
688     int x, y;
689
690     /* 64-color encoding (each pixel in block is a different color) */
691     CHECK_STREAM_PTR(64);
692
693     for (y = 0; y < 8; y++) {
694         for (x = 0; x < 8; x++) {
695             *sg_output_plane++ = *sg_stream_ptr++;
696         }
697         sg_output_plane += sg_line_inc;
698     }
699
700     /* report success */
701     return 0;
702 }
703
704 static int ipvideo_decode_block_opcode_0xC(void)
705 {
706     int x, y;
707     unsigned char pix;
708
709     /* 16-color block encoding: each 2x2 block is a different color */
710     CHECK_STREAM_PTR(16);
711
712     for (y = 0; y < 8; y += 2) {
713         for (x = 0; x < 8; x += 2) {
714             pix = *sg_stream_ptr++;
715             *(sg_output_plane + x) = pix;
716             *(sg_output_plane + x + 1) = pix;
717             *(sg_output_plane + sg_stride + x) = pix;
718             *(sg_output_plane + sg_stride + x + 1) = pix;
719         }
720         sg_output_plane += sg_stride * 2;
721     }
722
723     /* report success */
724     return 0;
725 }
726
727 static int ipvideo_decode_block_opcode_0xD(void)
728 {
729     int x, y;
730     unsigned char P[4];
731     unsigned char index = 0;
732
733     /* 4-color block encoding: each 4x4 block is a different color */
734     CHECK_STREAM_PTR(4);
735
736     for (y = 0; y < 4; y++)
737         P[y] = *sg_stream_ptr++;
738
739     for (y = 0; y < 8; y++) {
740         if (y < 4)
741             index = 0;
742         else
743             index = 2;
744
745         for (x = 0; x < 8; x++) {
746             if (x == 4)
747                 index++;
748             *sg_output_plane++ = P[index];
749         }
750         sg_output_plane += sg_line_inc;
751     }
752
753     /* report success */
754     return 0;
755 }
756
757 static int ipvideo_decode_block_opcode_0xE(void)
758 {
759     int x, y;
760     unsigned char pix;
761
762     /* 1-color encoding: the whole block is 1 solid color */
763     CHECK_STREAM_PTR(1);
764     pix = *sg_stream_ptr++;
765
766     for (y = 0; y < 8; y++) {
767         for (x = 0; x < 8; x++) {
768             *sg_output_plane++ = pix;
769         }
770         sg_output_plane += sg_line_inc;
771     }
772
773     /* report success */
774     return 0;
775 }
776
777 static int ipvideo_decode_block_opcode_0xF(void)
778 {
779     int x, y;
780     unsigned char sample0, sample1;
781
782     /* dithered encoding */
783     CHECK_STREAM_PTR(2);
784     sample0 = *sg_stream_ptr++;
785     sample1 = *sg_stream_ptr++;
786
787     for (y = 0; y < 8; y++) {
788         for (x = 0; x < 8; x += 2) {
789             if (y & 1) {
790                 *sg_output_plane++ = sample1;
791                 *sg_output_plane++ = sample0;
792             } else {
793                 *sg_output_plane++ = sample0;
794                 *sg_output_plane++ = sample1;
795             }
796         }
797         sg_output_plane += sg_line_inc;
798     }
799
800     /* report success */
801     return 0;
802 }
803
804 static int (*ipvideo_decode_block[16])(void);
805
806 static void ipvideo_decode_opcodes(IpvideoContext *s)
807 {
808     int x, y;
809     int index = 0;
810     unsigned char opcode;
811     int ret;
812     int code_counts[16];
813     static int frame = 0;
814
815     debug_interplay("------------------ frame %d\n", frame);
816     frame++;
817
818     for (x = 0; x < 16; x++)
819         code_counts[x] = 0;
820
821     /* this is PAL8, so make the palette available */
822     if (s->avctx->pix_fmt == PIX_FMT_PAL8)
823         memcpy(s->current_frame.data[1], s->palette, PALETTE_COUNT * 4);
824
825     switch (s->avctx->pix_fmt) {
826
827     case PIX_FMT_PAL8:
828         sg_stride = s->current_frame.linesize[0];
829         sg_stream_ptr = s->buf + 14;  /* data starts 14 bytes in */
830         sg_stream_end = s->buf + s->size;
831         sg_line_inc = sg_stride - 8;
832         sg_current_plane = s->current_frame.data[0];
833         sg_last_plane = s->last_frame.data[0];
834         sg_upper_motion_limit_offset = (s->avctx->height - 8) * sg_stride
835             + s->avctx->width - 8;
836         sg_dsp = s->dsp;
837
838         for (y = 0; y < (sg_stride * s->avctx->height); y += sg_stride * 8) {
839             for (x = y; x < y + s->avctx->width; x += 8) {
840                 /* bottom nibble first, then top nibble (which makes it
841                  * hard to use a GetBitcontext) */
842                 if (index & 1)
843                     opcode = s->decoding_map[index >> 1] >> 4;
844                 else
845                     opcode = s->decoding_map[index >> 1] & 0xF;
846                 index++;
847
848                 debug_interplay("  block @ (%3d, %3d): encoding 0x%X, data ptr @ %p\n",
849                     x - y, y / sg_stride, opcode, sg_stream_ptr);
850                 code_counts[opcode]++;
851
852                 sg_output_plane = sg_current_plane + x;
853                 ret = ipvideo_decode_block[opcode]();
854                 if (ret != 0) {
855                     printf(" Interplay video: decode problem on frame %d, @ block (%d, %d)\n",
856                         frame, x - y, y / sg_stride);
857                     return;
858                 }
859             }
860         }
861         if ((sg_stream_ptr != sg_stream_end) &&
862             (sg_stream_ptr + 1 != sg_stream_end)) {
863             printf (" Interplay video: decode finished with %d bytes left over\n",
864                 sg_stream_end - sg_stream_ptr);
865         }
866         break;
867
868     default:
869         printf ("Interplay video: Unhandled video format\n");
870         break;
871     }
872
873 }
874
875 static int ipvideo_decode_init(AVCodecContext *avctx)
876 {
877     IpvideoContext *s = avctx->priv_data;
878
879     s->avctx = avctx;
880
881     if (s->avctx->extradata_size != sizeof(AVPaletteControl)) {
882         printf (" Interplay video: expected extradata_size of %d\n",
883             sizeof(AVPaletteControl));
884         return -1;
885     }
886
887     avctx->pix_fmt = PIX_FMT_PAL8;
888     avctx->has_b_frames = 0;
889     dsputil_init(&s->dsp, avctx);
890
891     s->first_frame = 1;
892
893     /* decoding map contains 4 bits of information per 8x8 block */
894     s->decoding_map_size = avctx->width * avctx->height / (8 * 8 * 2);
895
896     /* assign block decode functions */
897     ipvideo_decode_block[0x0] = ipvideo_decode_block_opcode_0x0_0x1;
898     ipvideo_decode_block[0x1] = ipvideo_decode_block_opcode_0x0_0x1;
899     ipvideo_decode_block[0x2] = ipvideo_decode_block_opcode_0x2;
900     ipvideo_decode_block[0x3] = ipvideo_decode_block_opcode_0x3;
901     ipvideo_decode_block[0x4] = ipvideo_decode_block_opcode_0x4;
902     ipvideo_decode_block[0x5] = ipvideo_decode_block_opcode_0x5;
903     ipvideo_decode_block[0x6] = ipvideo_decode_block_opcode_0x6;
904     ipvideo_decode_block[0x7] = ipvideo_decode_block_opcode_0x7;
905     ipvideo_decode_block[0x8] = ipvideo_decode_block_opcode_0x8;
906     ipvideo_decode_block[0x9] = ipvideo_decode_block_opcode_0x9;
907     ipvideo_decode_block[0xA] = ipvideo_decode_block_opcode_0xA;
908     ipvideo_decode_block[0xB] = ipvideo_decode_block_opcode_0xB;
909     ipvideo_decode_block[0xC] = ipvideo_decode_block_opcode_0xC;
910     ipvideo_decode_block[0xD] = ipvideo_decode_block_opcode_0xD;
911     ipvideo_decode_block[0xE] = ipvideo_decode_block_opcode_0xE;
912     ipvideo_decode_block[0xF] = ipvideo_decode_block_opcode_0xF;
913
914     return 0;
915 }
916
917 static int ipvideo_decode_frame(AVCodecContext *avctx,
918                                 void *data, int *data_size,
919                                 uint8_t *buf, int buf_size)
920 {
921     IpvideoContext *s = avctx->priv_data;
922     AVPaletteControl *palette_control = (AVPaletteControl *)avctx->extradata;
923
924     if (palette_control->palette_changed) {
925         /* load the new palette and reset the palette control */
926         ipvideo_new_palette(s, palette_control->palette);
927         palette_control->palette_changed = 0;
928     }
929
930     s->decoding_map = buf;
931     s->buf = buf + s->decoding_map_size;
932     s->size = buf_size - s->decoding_map_size;
933
934     if (avctx->get_buffer(avctx, &s->current_frame)) {
935         printf ("  Interplay Video: get_buffer() failed\n");
936         return -1;
937     }
938
939     ipvideo_decode_opcodes(s);
940
941     /* release the last frame if it is allocated */
942     if (s->first_frame)
943         s->first_frame = 0;
944     else
945         avctx->release_buffer(avctx, &s->last_frame);
946
947     /* shuffle frames */
948     s->last_frame = s->current_frame;
949
950     *data_size = sizeof(AVFrame);
951     *(AVFrame*)data = s->current_frame;
952
953     /* report that the buffer was completely consumed */
954     return buf_size;
955 }
956
957 static int ipvideo_decode_end(AVCodecContext *avctx)
958 {
959     IpvideoContext *s = avctx->priv_data;
960
961     /* release the last frame */
962     avctx->release_buffer(avctx, &s->last_frame);
963
964     return 0;
965 }
966
967 AVCodec interplay_video_decoder = {
968     "interplayvideo",
969     CODEC_TYPE_VIDEO,
970     CODEC_ID_INTERPLAY_VIDEO,
971     sizeof(IpvideoContext),
972     ipvideo_decode_init,
973     NULL,
974     ipvideo_decode_end,
975     ipvideo_decode_frame,
976     CODEC_CAP_DR1,
977 };