Statistics
| Branch: | Revision:

ffmpeg / libavcodec / interplayvideo.c @ 186447f8

History | View | Annotate | Download (28 KB)

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
};