Statistics
| Branch: | Revision:

ffmpeg / libavcodec / interplayvideo.c @ e3114eb1

History | View | Annotate | Download (24.2 KB)

1
/*
2
 * Interplay MVE Video Decoder
3
 * Copyright (C) 2003 the ffmpeg project
4
 *
5
 * This file is part of FFmpeg.
6
 *
7
 * FFmpeg is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
12
 * FFmpeg is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with FFmpeg; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
 */
21

    
22
/**
23
 * @file libavcodec/interplayvideo.c
24
 * Interplay MVE Video Decoder by Mike Melanson (melanson@pcisys.net)
25
 * For more information about the Interplay MVE format, visit:
26
 *   http://www.pcisys.net/~melanson/codecs/interplay-mve.txt
27
 * This code is written in such a way that the identifiers match up
28
 * with the encoding descriptions in the document.
29
 *
30
 * This decoder presently only supports a PAL8 output colorspace.
31
 *
32
 * An Interplay video frame consists of 2 parts: The decoding map and
33
 * the video data. A demuxer must load these 2 parts together in a single
34
 * buffer before sending it through the stream to this decoder.
35
 */
36

    
37
#include <stdio.h>
38
#include <stdlib.h>
39
#include <string.h>
40
#include <unistd.h>
41

    
42
#include "avcodec.h"
43
#include "bytestream.h"
44
#include "dsputil.h"
45

    
46
#define PALETTE_COUNT 256
47

    
48
/* debugging support */
49
#define DEBUG_INTERPLAY 0
50
#if DEBUG_INTERPLAY
51
#define debug_interplay(x,...) av_log(NULL, AV_LOG_DEBUG, x, __VA_ARGS__)
52
#else
53
static inline void debug_interplay(const char *format, ...) { }
54
#endif
55

    
56
typedef struct IpvideoContext {
57

    
58
    AVCodecContext *avctx;
59
    DSPContext dsp;
60
    AVFrame second_last_frame;
61
    AVFrame last_frame;
62
    AVFrame current_frame;
63
    const unsigned char *decoding_map;
64
    int decoding_map_size;
65

    
66
    const unsigned char *buf;
67
    int size;
68

    
69
    const unsigned char *stream_ptr;
70
    const unsigned char *stream_end;
71
    unsigned char *pixel_ptr;
72
    int line_inc;
73
    int stride;
74
    int upper_motion_limit_offset;
75

    
76
} IpvideoContext;
77

    
78
#define CHECK_STREAM_PTR(n) \
79
  if (s->stream_end - s->stream_ptr < n) { \
80
    av_log(s->avctx, AV_LOG_ERROR, "Interplay video warning: stream_ptr out of bounds (%p >= %p)\n", \
81
      s->stream_ptr + n, s->stream_end); \
82
    return -1; \
83
  }
84

    
85
static int copy_from(IpvideoContext *s, AVFrame *src, int delta_x, int delta_y)
86
{
87
    int current_offset = s->pixel_ptr - s->current_frame.data[0];
88
    int motion_offset = current_offset + delta_y * s->stride + delta_x;
89
    if (motion_offset < 0) {
90
        av_log(s->avctx, AV_LOG_ERROR, " Interplay video: motion offset < 0 (%d)\n", motion_offset);
91
        return -1;
92
    } else if (motion_offset > s->upper_motion_limit_offset) {
93
        av_log(s->avctx, AV_LOG_ERROR, " Interplay video: motion offset above limit (%d >= %d)\n",
94
            motion_offset, s->upper_motion_limit_offset);
95
        return -1;
96
    }
97
    s->dsp.put_pixels_tab[1][0](s->pixel_ptr, src->data[0] + motion_offset, s->stride, 8);
98
    return 0;
99
}
100

    
101
static int ipvideo_decode_block_opcode_0x0(IpvideoContext *s)
102
{
103
    return copy_from(s, &s->last_frame, 0, 0);
104
}
105

    
106
static int ipvideo_decode_block_opcode_0x1(IpvideoContext *s)
107
{
108
    return copy_from(s, &s->second_last_frame, 0, 0);
109
}
110

    
111
static int ipvideo_decode_block_opcode_0x2(IpvideoContext *s)
112
{
113
    unsigned char B;
114
    int x, y;
115

    
116
    /* copy block from 2 frames ago using a motion vector; need 1 more byte */
117
    CHECK_STREAM_PTR(1);
118
    B = *s->stream_ptr++;
119

    
120
    if (B < 56) {
121
        x = 8 + (B % 7);
122
        y = B / 7;
123
    } else {
124
        x = -14 + ((B - 56) % 29);
125
        y =   8 + ((B - 56) / 29);
126
    }
127

    
128
    debug_interplay ("    motion byte = %d, (x, y) = (%d, %d)\n", B, x, y);
129
    return copy_from(s, &s->second_last_frame, x, y);
130
}
131

    
132
static int ipvideo_decode_block_opcode_0x3(IpvideoContext *s)
133
{
134
    unsigned char B;
135
    int x, y;
136

    
137
    /* copy 8x8 block from current frame from an up/left block */
138

    
139
    /* need 1 more byte for motion */
140
    CHECK_STREAM_PTR(1);
141
    B = *s->stream_ptr++;
142

    
143
    if (B < 56) {
144
        x = -(8 + (B % 7));
145
        y = -(B / 7);
146
    } else {
147
        x = -(-14 + ((B - 56) % 29));
148
        y = -(  8 + ((B - 56) / 29));
149
    }
150

    
151
    debug_interplay ("    motion byte = %d, (x, y) = (%d, %d)\n", B, x, y);
152
    return copy_from(s, &s->current_frame, x, y);
153
}
154

    
155
static int ipvideo_decode_block_opcode_0x4(IpvideoContext *s)
156
{
157
    int x, y;
158
    unsigned char B, BL, BH;
159

    
160
    /* copy a block from the previous frame; need 1 more byte */
161
    CHECK_STREAM_PTR(1);
162

    
163
    B = *s->stream_ptr++;
164
    BL = B & 0x0F;
165
    BH = (B >> 4) & 0x0F;
166
    x = -8 + BL;
167
    y = -8 + BH;
168

    
169
    debug_interplay ("    motion byte = %d, (x, y) = (%d, %d)\n", B, x, y);
170
    return copy_from(s, &s->last_frame, x, y);
171
}
172

    
173
static int ipvideo_decode_block_opcode_0x5(IpvideoContext *s)
174
{
175
    signed char x, y;
176

    
177
    /* copy a block from the previous frame using an expanded range;
178
     * need 2 more bytes */
179
    CHECK_STREAM_PTR(2);
180

    
181
    x = *s->stream_ptr++;
182
    y = *s->stream_ptr++;
183

    
184
    debug_interplay ("    motion bytes = %d, %d\n", x, y);
185
    return copy_from(s, &s->last_frame, x, y);
186
}
187

    
188
static int ipvideo_decode_block_opcode_0x6(IpvideoContext *s)
189
{
190
    /* mystery opcode? skip multiple blocks? */
191
    av_log(s->avctx, AV_LOG_ERROR, "  Interplay video: Help! Mystery opcode 0x6 seen\n");
192

    
193
    /* report success */
194
    return 0;
195
}
196

    
197
static int ipvideo_decode_block_opcode_0x7(IpvideoContext *s)
198
{
199
    int x, y;
200
    unsigned char P0, P1;
201
    unsigned int flags;
202

    
203
    /* 2-color encoding */
204
    CHECK_STREAM_PTR(2);
205

    
206
    P0 = *s->stream_ptr++;
207
    P1 = *s->stream_ptr++;
208

    
209
    if (P0 <= P1) {
210

    
211
        /* need 8 more bytes from the stream */
212
        CHECK_STREAM_PTR(8);
213

    
214
        for (y = 0; y < 8; y++) {
215
            flags = *s->stream_ptr++;
216
            for (x = 0x01; x <= 0x80; x <<= 1) {
217
                if (flags & x)
218
                    *s->pixel_ptr++ = P1;
219
                else
220
                    *s->pixel_ptr++ = P0;
221
            }
222
            s->pixel_ptr += s->line_inc;
223
        }
224

    
225
    } else {
226

    
227
        /* need 2 more bytes from the stream */
228
        CHECK_STREAM_PTR(2);
229

    
230
        flags = bytestream_get_le16(&s->stream_ptr);
231
        for (y = 0; y < 8; y += 2) {
232
            for (x = 0; x < 8; x += 2, flags >>= 1) {
233
                if (flags & 1) {
234
                    *(s->pixel_ptr + x) = P1;
235
                    *(s->pixel_ptr + x + 1) = P1;
236
                    *(s->pixel_ptr + s->stride + x) = P1;
237
                    *(s->pixel_ptr + s->stride + x + 1) = P1;
238
                } else {
239
                    *(s->pixel_ptr + x) = P0;
240
                    *(s->pixel_ptr + x + 1) = P0;
241
                    *(s->pixel_ptr + s->stride + x) = P0;
242
                    *(s->pixel_ptr + s->stride + x + 1) = P0;
243
                }
244
            }
245
            s->pixel_ptr += s->stride * 2;
246
        }
247
    }
248

    
249
    /* report success */
250
    return 0;
251
}
252

    
253
static int ipvideo_decode_block_opcode_0x8(IpvideoContext *s)
254
{
255
    int x, y;
256
    unsigned char P[8];
257
    unsigned char B[8];
258
    unsigned int flags = 0;
259
    unsigned char P0 = 0, P1 = 0;
260
    int lower_half = 0;
261

    
262
    /* 2-color encoding for each 4x4 quadrant, or 2-color encoding on
263
     * either top and bottom or left and right halves */
264
    CHECK_STREAM_PTR(2);
265

    
266
    P[0] = *s->stream_ptr++;
267
    P[1] = *s->stream_ptr++;
268

    
269
    if (P[0] <= P[1]) {
270

    
271
        /* need 12 more bytes */
272
        CHECK_STREAM_PTR(12);
273
        B[0] = *s->stream_ptr++;  B[1] = *s->stream_ptr++;
274
        P[2] = *s->stream_ptr++;  P[3] = *s->stream_ptr++;
275
        B[2] = *s->stream_ptr++;  B[3] = *s->stream_ptr++;
276
        P[4] = *s->stream_ptr++;  P[5] = *s->stream_ptr++;
277
        B[4] = *s->stream_ptr++;  B[5] = *s->stream_ptr++;
278
        P[6] = *s->stream_ptr++;  P[7] = *s->stream_ptr++;
279
        B[6] = *s->stream_ptr++;  B[7] = *s->stream_ptr++;
280

    
281
        for (y = 0; y < 8; y++) {
282

    
283
            /* time to reload flags? */
284
            if (y == 0) {
285
                flags =
286
                    ((B[0] & 0xF0) <<  4) | ((B[4] & 0xF0) <<  8) |
287
                    ((B[0] & 0x0F)      ) | ((B[4] & 0x0F) <<  4) |
288
                    ((B[1] & 0xF0) << 20) | ((B[5] & 0xF0) << 24) |
289
                    ((B[1] & 0x0F) << 16) | ((B[5] & 0x0F) << 20);
290
                lower_half = 0;  /* still on top half */
291
            } else if (y == 4) {
292
                flags =
293
                    ((B[2] & 0xF0) <<  4) | ((B[6] & 0xF0) <<  8) |
294
                    ((B[2] & 0x0F)      ) | ((B[6] & 0x0F) <<  4) |
295
                    ((B[3] & 0xF0) << 20) | ((B[7] & 0xF0) << 24) |
296
                    ((B[3] & 0x0F) << 16) | ((B[7] & 0x0F) << 20);
297
                lower_half = 2;
298
            }
299

    
300
            for (x = 0; x < 8; x++, flags >>= 1) {
301
                /* get the pixel values ready for this quadrant */
302
                if (x == 0) {
303
                    P0 = P[lower_half + 0];
304
                    P1 = P[lower_half + 1];
305
                } else if (x == 4) {
306
                    P0 = P[lower_half + 4];
307
                    P1 = P[lower_half + 5];
308
                }
309

    
310
                if (flags & 1)
311
                    *s->pixel_ptr++ = P1;
312
                else
313
                    *s->pixel_ptr++ = P0;
314
            }
315
            s->pixel_ptr += s->line_inc;
316
        }
317

    
318
    } else {
319

    
320
        /* need 10 more bytes */
321
        CHECK_STREAM_PTR(10);
322
        B[0] = *s->stream_ptr++;  B[1] = *s->stream_ptr++;
323
        B[2] = *s->stream_ptr++;  B[3] = *s->stream_ptr++;
324
        P[2] = *s->stream_ptr++;  P[3] = *s->stream_ptr++;
325
        B[4] = *s->stream_ptr++;  B[5] = *s->stream_ptr++;
326
        B[6] = *s->stream_ptr++;  B[7] = *s->stream_ptr++;
327

    
328
        if (P[2] <= P[3]) {
329

    
330
            /* vertical split; left & right halves are 2-color encoded */
331

    
332
            for (y = 0; y < 8; y++) {
333

    
334
                /* time to reload flags? */
335
                if (y == 0) {
336
                    flags =
337
                        ((B[0] & 0xF0) <<  4) | ((B[4] & 0xF0) <<  8) |
338
                        ((B[0] & 0x0F)      ) | ((B[4] & 0x0F) <<  4) |
339
                        ((B[1] & 0xF0) << 20) | ((B[5] & 0xF0) << 24) |
340
                        ((B[1] & 0x0F) << 16) | ((B[5] & 0x0F) << 20);
341
                } else if (y == 4) {
342
                    flags =
343
                        ((B[2] & 0xF0) <<  4) | ((B[6] & 0xF0) <<  8) |
344
                        ((B[2] & 0x0F)      ) | ((B[6] & 0x0F) <<  4) |
345
                        ((B[3] & 0xF0) << 20) | ((B[7] & 0xF0) << 24) |
346
                        ((B[3] & 0x0F) << 16) | ((B[7] & 0x0F) << 20);
347
                }
348

    
349
                for (x = 0; x < 8; x++, flags >>= 1) {
350
                    /* get the pixel values ready for this half */
351
                    if (x == 0) {
352
                        P0 = P[0];
353
                        P1 = P[1];
354
                    } else if (x == 4) {
355
                        P0 = P[2];
356
                        P1 = P[3];
357
                    }
358

    
359
                    if (flags & 1)
360
                        *s->pixel_ptr++ = P1;
361
                    else
362
                        *s->pixel_ptr++ = P0;
363
                }
364
                s->pixel_ptr += s->line_inc;
365
            }
366

    
367
        } else {
368

    
369
            /* horizontal split; top & bottom halves are 2-color encoded */
370

    
371
            for (y = 0; y < 8; y++) {
372
                int bitmask;
373

    
374
                flags = B[y];
375
                if (y == 0) {
376
                    P0 = P[0];
377
                    P1 = P[1];
378
                } else if (y == 4) {
379
                    P0 = P[2];
380
                    P1 = P[3];
381
                }
382

    
383
                for (bitmask = 0x01; bitmask <= 0x80; bitmask <<= 1) {
384

    
385
                    if (flags & bitmask)
386
                        *s->pixel_ptr++ = P1;
387
                    else
388
                        *s->pixel_ptr++ = P0;
389
                }
390
                s->pixel_ptr += s->line_inc;
391
            }
392
        }
393
    }
394

    
395
    /* report success */
396
    return 0;
397
}
398

    
399
static int ipvideo_decode_block_opcode_0x9(IpvideoContext *s)
400
{
401
    int x, y;
402
    unsigned char P[4];
403
    unsigned int flags = 0;
404
    unsigned char pix;
405

    
406
    /* 4-color encoding */
407
    CHECK_STREAM_PTR(4);
408

    
409
    memcpy(P, s->stream_ptr, 4);
410
    s->stream_ptr += 4;
411

    
412
    if ((P[0] <= P[1]) && (P[2] <= P[3])) {
413

    
414
        /* 1 of 4 colors for each pixel, need 16 more bytes */
415
        CHECK_STREAM_PTR(16);
416

    
417
        for (y = 0; y < 8; y++) {
418
            /* get the next set of 8 2-bit flags */
419
            flags = bytestream_get_le16(&s->stream_ptr);
420
            for (x = 0; x < 8; x++, flags >>= 2) {
421
                *s->pixel_ptr++ = P[flags & 0x03];
422
            }
423
            s->pixel_ptr += s->line_inc;
424
        }
425

    
426
    } else if ((P[0] <= P[1]) && (P[2] > P[3])) {
427

    
428
        /* 1 of 4 colors for each 2x2 block, need 4 more bytes */
429
        CHECK_STREAM_PTR(4);
430

    
431
        flags = bytestream_get_le32(&s->stream_ptr);
432

    
433
        for (y = 0; y < 8; y += 2) {
434
            for (x = 0; x < 8; x += 2, flags >>= 2) {
435
                pix = P[flags & 0x03];
436
                *(s->pixel_ptr + x) = pix;
437
                *(s->pixel_ptr + x + 1) = pix;
438
                *(s->pixel_ptr + s->stride + x) = pix;
439
                *(s->pixel_ptr + s->stride + x + 1) = pix;
440
            }
441
            s->pixel_ptr += s->stride * 2;
442
        }
443

    
444
    } else if ((P[0] > P[1]) && (P[2] <= P[3])) {
445

    
446
        /* 1 of 4 colors for each 2x1 block, need 8 more bytes */
447
        CHECK_STREAM_PTR(8);
448

    
449
        for (y = 0; y < 8; y++) {
450
            /* time to reload flags? */
451
            if ((y == 0) || (y == 4)) {
452
                flags = bytestream_get_le32(&s->stream_ptr);
453
            }
454
            for (x = 0; x < 8; x += 2, flags >>= 2) {
455
                pix = P[flags & 0x03];
456
                *(s->pixel_ptr + x) = pix;
457
                *(s->pixel_ptr + x + 1) = pix;
458
            }
459
            s->pixel_ptr += s->stride;
460
        }
461

    
462
    } else {
463

    
464
        /* 1 of 4 colors for each 1x2 block, need 8 more bytes */
465
        CHECK_STREAM_PTR(8);
466

    
467
        for (y = 0; y < 8; y += 2) {
468
            /* time to reload flags? */
469
            if ((y == 0) || (y == 4)) {
470
                flags = bytestream_get_le32(&s->stream_ptr);
471
            }
472
            for (x = 0; x < 8; x++, flags >>= 2) {
473
                pix = P[flags & 0x03];
474
                *(s->pixel_ptr + x) = pix;
475
                *(s->pixel_ptr + s->stride + x) = pix;
476
            }
477
            s->pixel_ptr += s->stride * 2;
478
        }
479
    }
480

    
481
    /* report success */
482
    return 0;
483
}
484

    
485
static int ipvideo_decode_block_opcode_0xA(IpvideoContext *s)
486
{
487
    int x, y;
488
    unsigned char P[16];
489
    unsigned char B[16];
490
    int flags = 0;
491
    int index;
492
    int split;
493
    int lower_half;
494

    
495
    /* 4-color encoding for each 4x4 quadrant, or 4-color encoding on
496
     * either top and bottom or left and right halves */
497
    CHECK_STREAM_PTR(4);
498

    
499
    memcpy(P, s->stream_ptr, 4);
500
    s->stream_ptr += 4;
501

    
502
    if (P[0] <= P[1]) {
503

    
504
        /* 4-color encoding for each quadrant; need 28 more bytes */
505
        CHECK_STREAM_PTR(28);
506

    
507
        memcpy(B, s->stream_ptr, 4);
508
        s->stream_ptr += 4;
509
        for (y = 4; y < 16; y += 4) {
510
            memcpy(P + y, s->stream_ptr, 4);
511
            s->stream_ptr += 4;
512
            memcpy(B + y, s->stream_ptr, 4);
513
            s->stream_ptr += 4;
514
        }
515

    
516
        for (y = 0; y < 8; y++) {
517

    
518
            lower_half = (y >= 4) ? 4 : 0;
519
            flags = (B[y + 8] << 8) | B[y];
520

    
521
            for (x = 0; x < 8; x++, flags >>= 2) {
522
                split = (x >= 4) ? 8 : 0;
523
                index = split + lower_half + (flags & 0x03);
524
                *s->pixel_ptr++ = P[index];
525
            }
526

    
527
            s->pixel_ptr += s->line_inc;
528
        }
529

    
530
    } else {
531

    
532
        /* 4-color encoding for either left and right or top and bottom
533
         * halves; need 20 more bytes */
534
        CHECK_STREAM_PTR(20);
535

    
536
        memcpy(B, s->stream_ptr, 8);
537
        s->stream_ptr += 8;
538
        memcpy(P + 4, s->stream_ptr, 4);
539
        s->stream_ptr += 4;
540
        memcpy(B + 8, s->stream_ptr, 8);
541
        s->stream_ptr += 8;
542

    
543
        if (P[4] <= P[5]) {
544

    
545
            /* block is divided into left and right halves */
546
            for (y = 0; y < 8; y++) {
547

    
548
                flags = (B[y + 8] << 8) | B[y];
549
                split = 0;
550

    
551
                for (x = 0; x < 8; x++, flags >>= 2) {
552
                    if (x == 4)
553
                        split = 4;
554
                    *s->pixel_ptr++ = P[split + (flags & 0x03)];
555
                }
556

    
557
                s->pixel_ptr += s->line_inc;
558
            }
559

    
560
        } else {
561

    
562
            /* block is divided into top and bottom halves */
563
            split = 0;
564
            for (y = 0; y < 8; y++) {
565

    
566
                flags = (B[y * 2 + 1] << 8) | B[y * 2];
567
                if (y == 4)
568
                    split = 4;
569

    
570
                for (x = 0; x < 8; x++, flags >>= 2)
571
                    *s->pixel_ptr++ = P[split + (flags & 0x03)];
572

    
573
                s->pixel_ptr += s->line_inc;
574
            }
575
        }
576
    }
577

    
578
    /* report success */
579
    return 0;
580
}
581

    
582
static int ipvideo_decode_block_opcode_0xB(IpvideoContext *s)
583
{
584
    int y;
585

    
586
    /* 64-color encoding (each pixel in block is a different color) */
587
    CHECK_STREAM_PTR(64);
588

    
589
    for (y = 0; y < 8; y++) {
590
        memcpy(s->pixel_ptr, s->stream_ptr, 8);
591
        s->stream_ptr += 8;
592
        s->pixel_ptr  += s->stride;
593
    }
594

    
595
    /* report success */
596
    return 0;
597
}
598

    
599
static int ipvideo_decode_block_opcode_0xC(IpvideoContext *s)
600
{
601
    int x, y;
602
    unsigned char pix;
603

    
604
    /* 16-color block encoding: each 2x2 block is a different color */
605
    CHECK_STREAM_PTR(16);
606

    
607
    for (y = 0; y < 8; y += 2) {
608
        for (x = 0; x < 8; x += 2) {
609
            pix = *s->stream_ptr++;
610
            *(s->pixel_ptr + x) = pix;
611
            *(s->pixel_ptr + x + 1) = pix;
612
            *(s->pixel_ptr + s->stride + x) = pix;
613
            *(s->pixel_ptr + s->stride + x + 1) = pix;
614
        }
615
        s->pixel_ptr += s->stride * 2;
616
    }
617

    
618
    /* report success */
619
    return 0;
620
}
621

    
622
static int ipvideo_decode_block_opcode_0xD(IpvideoContext *s)
623
{
624
    int y;
625
    unsigned char P[4];
626
    unsigned char index = 0;
627

    
628
    /* 4-color block encoding: each 4x4 block is a different color */
629
    CHECK_STREAM_PTR(4);
630

    
631
    memcpy(P, s->stream_ptr, 4);
632
    s->stream_ptr += 4;
633

    
634
    for (y = 0; y < 8; y++) {
635
        if (y < 4)
636
            index = 0;
637
        else
638
            index = 2;
639

    
640
        memset(s->pixel_ptr    , P[index    ], 4);
641
        memset(s->pixel_ptr + 4, P[index + 1], 4);
642
        s->pixel_ptr += s->stride;
643
    }
644

    
645
    /* report success */
646
    return 0;
647
}
648

    
649
static int ipvideo_decode_block_opcode_0xE(IpvideoContext *s)
650
{
651
    int y;
652
    unsigned char pix;
653

    
654
    /* 1-color encoding: the whole block is 1 solid color */
655
    CHECK_STREAM_PTR(1);
656
    pix = *s->stream_ptr++;
657

    
658
    for (y = 0; y < 8; y++) {
659
        memset(s->pixel_ptr, pix, 8);
660
        s->pixel_ptr += s->stride;
661
    }
662

    
663
    /* report success */
664
    return 0;
665
}
666

    
667
static int ipvideo_decode_block_opcode_0xF(IpvideoContext *s)
668
{
669
    int x, y;
670
    unsigned char sample0, sample1;
671

    
672
    /* dithered encoding */
673
    CHECK_STREAM_PTR(2);
674
    sample0 = *s->stream_ptr++;
675
    sample1 = *s->stream_ptr++;
676

    
677
    for (y = 0; y < 8; y++) {
678
        for (x = 0; x < 8; x += 2) {
679
            if (y & 1) {
680
                *s->pixel_ptr++ = sample1;
681
                *s->pixel_ptr++ = sample0;
682
            } else {
683
                *s->pixel_ptr++ = sample0;
684
                *s->pixel_ptr++ = sample1;
685
            }
686
        }
687
        s->pixel_ptr += s->line_inc;
688
    }
689

    
690
    /* report success */
691
    return 0;
692
}
693

    
694
static int (* const ipvideo_decode_block[])(IpvideoContext *s) = {
695
    ipvideo_decode_block_opcode_0x0, ipvideo_decode_block_opcode_0x1,
696
    ipvideo_decode_block_opcode_0x2, ipvideo_decode_block_opcode_0x3,
697
    ipvideo_decode_block_opcode_0x4, ipvideo_decode_block_opcode_0x5,
698
    ipvideo_decode_block_opcode_0x6, ipvideo_decode_block_opcode_0x7,
699
    ipvideo_decode_block_opcode_0x8, ipvideo_decode_block_opcode_0x9,
700
    ipvideo_decode_block_opcode_0xA, ipvideo_decode_block_opcode_0xB,
701
    ipvideo_decode_block_opcode_0xC, ipvideo_decode_block_opcode_0xD,
702
    ipvideo_decode_block_opcode_0xE, ipvideo_decode_block_opcode_0xF,
703
};
704

    
705
static void ipvideo_decode_opcodes(IpvideoContext *s)
706
{
707
    int x, y;
708
    int index = 0;
709
    unsigned char opcode;
710
    int ret;
711
    int code_counts[16] = {0};
712
    static int frame = 0;
713

    
714
    debug_interplay("------------------ frame %d\n", frame);
715
    frame++;
716

    
717
    /* this is PAL8, so make the palette available */
718
    memcpy(s->current_frame.data[1], s->avctx->palctrl->palette, PALETTE_COUNT * 4);
719

    
720
    s->stride = s->current_frame.linesize[0];
721
    s->stream_ptr = s->buf + 14;  /* data starts 14 bytes in */
722
    s->stream_end = s->buf + s->size;
723
    s->line_inc = s->stride - 8;
724
    s->upper_motion_limit_offset = (s->avctx->height - 8) * s->stride
725
        + s->avctx->width - 8;
726

    
727
    for (y = 0; y < (s->stride * s->avctx->height); y += s->stride * 8) {
728
        for (x = y; x < y + s->avctx->width; x += 8) {
729
            /* bottom nibble first, then top nibble (which makes it
730
             * hard to use a GetBitcontext) */
731
            if (index & 1)
732
                opcode = s->decoding_map[index >> 1] >> 4;
733
            else
734
                opcode = s->decoding_map[index >> 1] & 0xF;
735
            index++;
736

    
737
            debug_interplay("  block @ (%3d, %3d): encoding 0x%X, data ptr @ %p\n",
738
                x - y, y / s->stride, opcode, s->stream_ptr);
739
            code_counts[opcode]++;
740

    
741
            s->pixel_ptr = s->current_frame.data[0] + x;
742
            ret = ipvideo_decode_block[opcode](s);
743
            if (ret != 0) {
744
                av_log(s->avctx, AV_LOG_ERROR, " Interplay video: decode problem on frame %d, @ block (%d, %d)\n",
745
                    frame, x - y, y / s->stride);
746
                return;
747
            }
748
        }
749
    }
750
    if (s->stream_end - s->stream_ptr > 1) {
751
        av_log(s->avctx, AV_LOG_ERROR, " Interplay video: decode finished with %td bytes left over\n",
752
            s->stream_end - s->stream_ptr);
753
    }
754
}
755

    
756
static av_cold int ipvideo_decode_init(AVCodecContext *avctx)
757
{
758
    IpvideoContext *s = avctx->priv_data;
759

    
760
    s->avctx = avctx;
761

    
762
    if (s->avctx->palctrl == NULL) {
763
        av_log(avctx, AV_LOG_ERROR, " Interplay video: palette expected.\n");
764
        return -1;
765
    }
766

    
767
    avctx->pix_fmt = PIX_FMT_PAL8;
768
    dsputil_init(&s->dsp, avctx);
769

    
770
    /* decoding map contains 4 bits of information per 8x8 block */
771
    s->decoding_map_size = avctx->width * avctx->height / (8 * 8 * 2);
772

    
773
    s->current_frame.data[0] = s->last_frame.data[0] =
774
    s->second_last_frame.data[0] = NULL;
775

    
776
    return 0;
777
}
778

    
779
static int ipvideo_decode_frame(AVCodecContext *avctx,
780
                                void *data, int *data_size,
781
                                const uint8_t *buf, int buf_size)
782
{
783
    IpvideoContext *s = avctx->priv_data;
784
    AVPaletteControl *palette_control = avctx->palctrl;
785

    
786
    /* compressed buffer needs to be large enough to at least hold an entire
787
     * decoding map */
788
    if (buf_size < s->decoding_map_size)
789
        return buf_size;
790

    
791
    s->decoding_map = buf;
792
    s->buf = buf + s->decoding_map_size;
793
    s->size = buf_size - s->decoding_map_size;
794

    
795
    s->current_frame.reference = 3;
796
    if (avctx->get_buffer(avctx, &s->current_frame)) {
797
        av_log(avctx, AV_LOG_ERROR, "  Interplay Video: get_buffer() failed\n");
798
        return -1;
799
    }
800

    
801
    ipvideo_decode_opcodes(s);
802

    
803
    if (palette_control->palette_changed) {
804
        palette_control->palette_changed = 0;
805
        s->current_frame.palette_has_changed = 1;
806
    }
807

    
808
    *data_size = sizeof(AVFrame);
809
    *(AVFrame*)data = s->current_frame;
810

    
811
    /* shuffle frames */
812
    if (s->second_last_frame.data[0])
813
        avctx->release_buffer(avctx, &s->second_last_frame);
814
    s->second_last_frame = s->last_frame;
815
    s->last_frame = s->current_frame;
816
    s->current_frame.data[0] = NULL;  /* catch any access attempts */
817

    
818
    /* report that the buffer was completely consumed */
819
    return buf_size;
820
}
821

    
822
static av_cold int ipvideo_decode_end(AVCodecContext *avctx)
823
{
824
    IpvideoContext *s = avctx->priv_data;
825

    
826
    /* release the last frame */
827
    if (s->last_frame.data[0])
828
        avctx->release_buffer(avctx, &s->last_frame);
829
    if (s->second_last_frame.data[0])
830
        avctx->release_buffer(avctx, &s->second_last_frame);
831

    
832
    return 0;
833
}
834

    
835
AVCodec interplay_video_decoder = {
836
    "interplayvideo",
837
    CODEC_TYPE_VIDEO,
838
    CODEC_ID_INTERPLAY_VIDEO,
839
    sizeof(IpvideoContext),
840
    ipvideo_decode_init,
841
    NULL,
842
    ipvideo_decode_end,
843
    ipvideo_decode_frame,
844
    CODEC_CAP_DR1,
845
    .long_name = NULL_IF_CONFIG_SMALL("Interplay MVE video"),
846
};