Statistics
| Branch: | Revision:

ffmpeg / libavcodec / interplayvideo.c @ 2843502e

History | View | Annotate | Download (32.7 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
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

    
41
#include "avcodec.h"
42
#include "bytestream.h"
43
#include "dsputil.h"
44
#define ALT_BITSTREAM_READER_LE
45
#include "get_bits.h"
46

    
47
#define PALETTE_COUNT 256
48

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

    
57
typedef struct IpvideoContext {
58

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

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

    
70
    int is_16bpp;
71
    const unsigned char *stream_ptr;
72
    const unsigned char *stream_end;
73
    const uint8_t *mv_ptr;
74
    const uint8_t *mv_end;
75
    unsigned char *pixel_ptr;
76
    int line_inc;
77
    int stride;
78
    int upper_motion_limit_offset;
79

    
80
} IpvideoContext;
81

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

    
89
static int copy_from(IpvideoContext *s, AVFrame *src, int delta_x, int delta_y)
90
{
91
    int current_offset = s->pixel_ptr - s->current_frame.data[0];
92
    int motion_offset = current_offset + delta_y * s->current_frame.linesize[0]
93
                       + delta_x * (1 + s->is_16bpp);
94
    if (motion_offset < 0) {
95
        av_log(s->avctx, AV_LOG_ERROR, " Interplay video: motion offset < 0 (%d)\n", motion_offset);
96
        return -1;
97
    } else if (motion_offset > s->upper_motion_limit_offset) {
98
        av_log(s->avctx, AV_LOG_ERROR, " Interplay video: motion offset above limit (%d >= %d)\n",
99
            motion_offset, s->upper_motion_limit_offset);
100
        return -1;
101
    }
102
    if (src->data[0] == NULL) {
103
        av_log(s->avctx, AV_LOG_ERROR, "Invalid decode type, corrupted header?\n");
104
        return AVERROR(EINVAL);
105
    }
106
    s->dsp.put_pixels_tab[!s->is_16bpp][0](s->pixel_ptr, src->data[0] + motion_offset,
107
                                           s->current_frame.linesize[0], 8);
108
    return 0;
109
}
110

    
111
static int ipvideo_decode_block_opcode_0x0(IpvideoContext *s)
112
{
113
    return copy_from(s, &s->last_frame, 0, 0);
114
}
115

    
116
static int ipvideo_decode_block_opcode_0x1(IpvideoContext *s)
117
{
118
    return copy_from(s, &s->second_last_frame, 0, 0);
119
}
120

    
121
static int ipvideo_decode_block_opcode_0x2(IpvideoContext *s)
122
{
123
    unsigned char B;
124
    int x, y;
125

    
126
    /* copy block from 2 frames ago using a motion vector; need 1 more byte */
127
    if (!s->is_16bpp) {
128
        CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 1);
129
        B = *s->stream_ptr++;
130
    } else {
131
        CHECK_STREAM_PTR(s->mv_ptr, s->mv_end, 1);
132
        B = *s->mv_ptr++;
133
    }
134

    
135
    if (B < 56) {
136
        x = 8 + (B % 7);
137
        y = B / 7;
138
    } else {
139
        x = -14 + ((B - 56) % 29);
140
        y =   8 + ((B - 56) / 29);
141
    }
142

    
143
    debug_interplay ("    motion byte = %d, (x, y) = (%d, %d)\n", B, x, y);
144
    return copy_from(s, &s->second_last_frame, x, y);
145
}
146

    
147
static int ipvideo_decode_block_opcode_0x3(IpvideoContext *s)
148
{
149
    unsigned char B;
150
    int x, y;
151

    
152
    /* copy 8x8 block from current frame from an up/left block */
153

    
154
    /* need 1 more byte for motion */
155
    if (!s->is_16bpp) {
156
        CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 1);
157
        B = *s->stream_ptr++;
158
    } else {
159
        CHECK_STREAM_PTR(s->mv_ptr, s->mv_end, 1);
160
        B = *s->mv_ptr++;
161
    }
162

    
163
    if (B < 56) {
164
        x = -(8 + (B % 7));
165
        y = -(B / 7);
166
    } else {
167
        x = -(-14 + ((B - 56) % 29));
168
        y = -(  8 + ((B - 56) / 29));
169
    }
170

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

    
175
static int ipvideo_decode_block_opcode_0x4(IpvideoContext *s)
176
{
177
    int x, y;
178
    unsigned char B, BL, BH;
179

    
180
    /* copy a block from the previous frame; need 1 more byte */
181
    if (!s->is_16bpp) {
182
        CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 1);
183
        B = *s->stream_ptr++;
184
    } else {
185
        CHECK_STREAM_PTR(s->mv_ptr, s->mv_end, 1);
186
        B = *s->mv_ptr++;
187
    }
188

    
189
    BL = B & 0x0F;
190
    BH = (B >> 4) & 0x0F;
191
    x = -8 + BL;
192
    y = -8 + BH;
193

    
194
    debug_interplay ("    motion byte = %d, (x, y) = (%d, %d)\n", B, x, y);
195
    return copy_from(s, &s->last_frame, x, y);
196
}
197

    
198
static int ipvideo_decode_block_opcode_0x5(IpvideoContext *s)
199
{
200
    signed char x, y;
201

    
202
    /* copy a block from the previous frame using an expanded range;
203
     * need 2 more bytes */
204
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2);
205

    
206
    x = *s->stream_ptr++;
207
    y = *s->stream_ptr++;
208

    
209
    debug_interplay ("    motion bytes = %d, %d\n", x, y);
210
    return copy_from(s, &s->last_frame, x, y);
211
}
212

    
213
static int ipvideo_decode_block_opcode_0x6(IpvideoContext *s)
214
{
215
    /* mystery opcode? skip multiple blocks? */
216
    av_log(s->avctx, AV_LOG_ERROR, "  Interplay video: Help! Mystery opcode 0x6 seen\n");
217

    
218
    /* report success */
219
    return 0;
220
}
221

    
222
static int ipvideo_decode_block_opcode_0x7(IpvideoContext *s)
223
{
224
    int x, y;
225
    unsigned char P[2];
226
    unsigned int flags;
227

    
228
    /* 2-color encoding */
229
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2);
230

    
231
    P[0] = *s->stream_ptr++;
232
    P[1] = *s->stream_ptr++;
233

    
234
    if (P[0] <= P[1]) {
235

    
236
        /* need 8 more bytes from the stream */
237
        CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 8);
238

    
239
        for (y = 0; y < 8; y++) {
240
            flags = *s->stream_ptr++ | 0x100;
241
            for (; flags != 1; flags >>= 1)
242
                *s->pixel_ptr++ = P[flags & 1];
243
            s->pixel_ptr += s->line_inc;
244
        }
245

    
246
    } else {
247

    
248
        /* need 2 more bytes from the stream */
249
        CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2);
250

    
251
        flags = bytestream_get_le16(&s->stream_ptr);
252
        for (y = 0; y < 8; y += 2) {
253
            for (x = 0; x < 8; x += 2, flags >>= 1) {
254
                s->pixel_ptr[x                ] =
255
                s->pixel_ptr[x + 1            ] =
256
                s->pixel_ptr[x +     s->stride] =
257
                s->pixel_ptr[x + 1 + s->stride] = P[flags & 1];
258
            }
259
            s->pixel_ptr += s->stride * 2;
260
        }
261
    }
262

    
263
    /* report success */
264
    return 0;
265
}
266

    
267
static int ipvideo_decode_block_opcode_0x8(IpvideoContext *s)
268
{
269
    int x, y;
270
    unsigned char P[2];
271
    unsigned int flags = 0;
272

    
273
    /* 2-color encoding for each 4x4 quadrant, or 2-color encoding on
274
     * either top and bottom or left and right halves */
275
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2);
276

    
277
    P[0] = *s->stream_ptr++;
278
    P[1] = *s->stream_ptr++;
279

    
280
    if (P[0] <= P[1]) {
281

    
282
        CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 14);
283
        s->stream_ptr -= 2;
284

    
285
        for (y = 0; y < 16; y++) {
286
            // new values for each 4x4 block
287
            if (!(y & 3)) {
288
                P[0] = *s->stream_ptr++; P[1] = *s->stream_ptr++;
289
                flags = bytestream_get_le16(&s->stream_ptr);
290
            }
291

    
292
            for (x = 0; x < 4; x++, flags >>= 1)
293
                *s->pixel_ptr++ = P[flags & 1];
294
            s->pixel_ptr += s->stride - 4;
295
            // switch to right half
296
            if (y == 7) s->pixel_ptr -= 8 * s->stride - 4;
297
        }
298

    
299
    } else {
300

    
301
        /* need 10 more bytes */
302
        CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 10);
303

    
304
        if (s->stream_ptr[4] <= s->stream_ptr[5]) {
305

    
306
            flags = bytestream_get_le32(&s->stream_ptr);
307

    
308
            /* vertical split; left & right halves are 2-color encoded */
309

    
310
            for (y = 0; y < 16; y++) {
311
                for (x = 0; x < 4; x++, flags >>= 1)
312
                    *s->pixel_ptr++ = P[flags & 1];
313
                s->pixel_ptr += s->stride - 4;
314
                // switch to right half
315
                if (y == 7) {
316
                    s->pixel_ptr -= 8 * s->stride - 4;
317
                    P[0] = *s->stream_ptr++; P[1] = *s->stream_ptr++;
318
                    flags = bytestream_get_le32(&s->stream_ptr);
319
                }
320
            }
321

    
322
        } else {
323

    
324
            /* horizontal split; top & bottom halves are 2-color encoded */
325

    
326
            for (y = 0; y < 8; y++) {
327
                if (y == 4) {
328
                    P[0] = *s->stream_ptr++;
329
                    P[1] = *s->stream_ptr++;
330
                }
331
                flags = *s->stream_ptr++ | 0x100;
332

    
333
                for (; flags != 1; flags >>= 1)
334
                    *s->pixel_ptr++ = P[flags & 1];
335
                s->pixel_ptr += s->line_inc;
336
            }
337
        }
338
    }
339

    
340
    /* report success */
341
    return 0;
342
}
343

    
344
static int ipvideo_decode_block_opcode_0x9(IpvideoContext *s)
345
{
346
    int x, y;
347
    unsigned char P[4];
348

    
349
    /* 4-color encoding */
350
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 4);
351

    
352
    memcpy(P, s->stream_ptr, 4);
353
    s->stream_ptr += 4;
354

    
355
    if (P[0] <= P[1]) {
356
        if (P[2] <= P[3]) {
357

    
358
            /* 1 of 4 colors for each pixel, need 16 more bytes */
359
            CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 16);
360

    
361
            for (y = 0; y < 8; y++) {
362
                /* get the next set of 8 2-bit flags */
363
                int flags = bytestream_get_le16(&s->stream_ptr);
364
                for (x = 0; x < 8; x++, flags >>= 2)
365
                    *s->pixel_ptr++ = P[flags & 0x03];
366
                s->pixel_ptr += s->line_inc;
367
            }
368

    
369
        } else {
370
            uint32_t flags;
371

    
372
            /* 1 of 4 colors for each 2x2 block, need 4 more bytes */
373
            CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 4);
374

    
375
            flags = bytestream_get_le32(&s->stream_ptr);
376

    
377
            for (y = 0; y < 8; y += 2) {
378
                for (x = 0; x < 8; x += 2, flags >>= 2) {
379
                    s->pixel_ptr[x                ] =
380
                    s->pixel_ptr[x + 1            ] =
381
                    s->pixel_ptr[x +     s->stride] =
382
                    s->pixel_ptr[x + 1 + s->stride] = P[flags & 0x03];
383
                }
384
                s->pixel_ptr += s->stride * 2;
385
            }
386

    
387
        }
388
    } else {
389
        uint64_t flags;
390

    
391
        /* 1 of 4 colors for each 2x1 or 1x2 block, need 8 more bytes */
392
        CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 8);
393

    
394
        flags = bytestream_get_le64(&s->stream_ptr);
395
        if (P[2] <= P[3]) {
396
            for (y = 0; y < 8; y++) {
397
                for (x = 0; x < 8; x += 2, flags >>= 2) {
398
                    s->pixel_ptr[x    ] =
399
                    s->pixel_ptr[x + 1] = P[flags & 0x03];
400
                }
401
                s->pixel_ptr += s->stride;
402
            }
403
        } else {
404
            for (y = 0; y < 8; y += 2) {
405
                for (x = 0; x < 8; x++, flags >>= 2) {
406
                    s->pixel_ptr[x            ] =
407
                    s->pixel_ptr[x + s->stride] = P[flags & 0x03];
408
                }
409
                s->pixel_ptr += s->stride * 2;
410
            }
411
        }
412
    }
413

    
414
    /* report success */
415
    return 0;
416
}
417

    
418
static int ipvideo_decode_block_opcode_0xA(IpvideoContext *s)
419
{
420
    int x, y;
421
    unsigned char P[4];
422
    int flags = 0;
423

    
424
    /* 4-color encoding for each 4x4 quadrant, or 4-color encoding on
425
     * either top and bottom or left and right halves */
426
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 24);
427

    
428
    if (s->stream_ptr[0] <= s->stream_ptr[1]) {
429

    
430
        /* 4-color encoding for each quadrant; need 32 bytes */
431
        CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 32);
432

    
433
        for (y = 0; y < 16; y++) {
434
            // new values for each 4x4 block
435
            if (!(y & 3)) {
436
                memcpy(P, s->stream_ptr, 4);
437
                s->stream_ptr += 4;
438
                flags = bytestream_get_le32(&s->stream_ptr);
439
            }
440

    
441
            for (x = 0; x < 4; x++, flags >>= 2)
442
                *s->pixel_ptr++ = P[flags & 0x03];
443

    
444
            s->pixel_ptr += s->stride - 4;
445
            // switch to right half
446
            if (y == 7) s->pixel_ptr -= 8 * s->stride - 4;
447
        }
448

    
449
    } else {
450
        // vertical split?
451
        int vert = s->stream_ptr[12] <= s->stream_ptr[13];
452
        uint64_t flags = 0;
453

    
454
        /* 4-color encoding for either left and right or top and bottom
455
         * halves */
456

    
457
        for (y = 0; y < 16; y++) {
458
            // load values for each half
459
            if (!(y & 7)) {
460
                memcpy(P, s->stream_ptr, 4);
461
                s->stream_ptr += 4;
462
                flags = bytestream_get_le64(&s->stream_ptr);
463
            }
464

    
465
            for (x = 0; x < 4; x++, flags >>= 2)
466
                *s->pixel_ptr++ = P[flags & 0x03];
467

    
468
            if (vert) {
469
                s->pixel_ptr += s->stride - 4;
470
                // switch to right half
471
                if (y == 7) s->pixel_ptr -= 8 * s->stride - 4;
472
            } else if (y & 1) s->pixel_ptr += s->line_inc;
473
        }
474
    }
475

    
476
    /* report success */
477
    return 0;
478
}
479

    
480
static int ipvideo_decode_block_opcode_0xB(IpvideoContext *s)
481
{
482
    int y;
483

    
484
    /* 64-color encoding (each pixel in block is a different color) */
485
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 64);
486

    
487
    for (y = 0; y < 8; y++) {
488
        memcpy(s->pixel_ptr, s->stream_ptr, 8);
489
        s->stream_ptr += 8;
490
        s->pixel_ptr  += s->stride;
491
    }
492

    
493
    /* report success */
494
    return 0;
495
}
496

    
497
static int ipvideo_decode_block_opcode_0xC(IpvideoContext *s)
498
{
499
    int x, y;
500

    
501
    /* 16-color block encoding: each 2x2 block is a different color */
502
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 16);
503

    
504
    for (y = 0; y < 8; y += 2) {
505
        for (x = 0; x < 8; x += 2) {
506
            s->pixel_ptr[x                ] =
507
            s->pixel_ptr[x + 1            ] =
508
            s->pixel_ptr[x +     s->stride] =
509
            s->pixel_ptr[x + 1 + s->stride] = *s->stream_ptr++;
510
        }
511
        s->pixel_ptr += s->stride * 2;
512
    }
513

    
514
    /* report success */
515
    return 0;
516
}
517

    
518
static int ipvideo_decode_block_opcode_0xD(IpvideoContext *s)
519
{
520
    int y;
521
    unsigned char P[2];
522

    
523
    /* 4-color block encoding: each 4x4 block is a different color */
524
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 4);
525

    
526
    for (y = 0; y < 8; y++) {
527
        if (!(y & 3)) {
528
            P[0] = *s->stream_ptr++;
529
            P[1] = *s->stream_ptr++;
530
        }
531
        memset(s->pixel_ptr,     P[0], 4);
532
        memset(s->pixel_ptr + 4, P[1], 4);
533
        s->pixel_ptr += s->stride;
534
    }
535

    
536
    /* report success */
537
    return 0;
538
}
539

    
540
static int ipvideo_decode_block_opcode_0xE(IpvideoContext *s)
541
{
542
    int y;
543
    unsigned char pix;
544

    
545
    /* 1-color encoding: the whole block is 1 solid color */
546
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 1);
547
    pix = *s->stream_ptr++;
548

    
549
    for (y = 0; y < 8; y++) {
550
        memset(s->pixel_ptr, pix, 8);
551
        s->pixel_ptr += s->stride;
552
    }
553

    
554
    /* report success */
555
    return 0;
556
}
557

    
558
static int ipvideo_decode_block_opcode_0xF(IpvideoContext *s)
559
{
560
    int x, y;
561
    unsigned char sample[2];
562

    
563
    /* dithered encoding */
564
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2);
565
    sample[0] = *s->stream_ptr++;
566
    sample[1] = *s->stream_ptr++;
567

    
568
    for (y = 0; y < 8; y++) {
569
        for (x = 0; x < 8; x += 2) {
570
            *s->pixel_ptr++ = sample[  y & 1 ];
571
            *s->pixel_ptr++ = sample[!(y & 1)];
572
        }
573
        s->pixel_ptr += s->line_inc;
574
    }
575

    
576
    /* report success */
577
    return 0;
578
}
579

    
580
static int ipvideo_decode_block_opcode_0x6_16(IpvideoContext *s)
581
{
582
    signed char x, y;
583

    
584
    /* copy a block from the second last frame using an expanded range */
585
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2);
586

    
587
    x = *s->stream_ptr++;
588
    y = *s->stream_ptr++;
589

    
590
    debug_interplay ("    motion bytes = %d, %d\n", x, y);
591
    return copy_from(s, &s->second_last_frame, x, y);
592
}
593

    
594
static int ipvideo_decode_block_opcode_0x7_16(IpvideoContext *s)
595
{
596
    int x, y;
597
    uint16_t P[2];
598
    unsigned int flags;
599
    uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
600

    
601
    /* 2-color encoding */
602
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 4);
603

    
604
    P[0] = bytestream_get_le16(&s->stream_ptr);
605
    P[1] = bytestream_get_le16(&s->stream_ptr);
606

    
607
    if (!(P[0] & 0x8000)) {
608

    
609
        CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 8);
610

    
611
        for (y = 0; y < 8; y++) {
612
            flags = *s->stream_ptr++ | 0x100;
613
            for (; flags != 1; flags >>= 1)
614
                *pixel_ptr++ = P[flags & 1];
615
            pixel_ptr += s->line_inc;
616
        }
617

    
618
    } else {
619

    
620
        CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2);
621

    
622
        flags = bytestream_get_le16(&s->stream_ptr);
623
        for (y = 0; y < 8; y += 2) {
624
            for (x = 0; x < 8; x += 2, flags >>= 1) {
625
                pixel_ptr[x                ] =
626
                pixel_ptr[x + 1            ] =
627
                pixel_ptr[x +     s->stride] =
628
                pixel_ptr[x + 1 + s->stride] = P[flags & 1];
629
            }
630
            pixel_ptr += s->stride * 2;
631
        }
632
    }
633

    
634
    return 0;
635
}
636

    
637
static int ipvideo_decode_block_opcode_0x8_16(IpvideoContext *s)
638
{
639
    int x, y;
640
    uint16_t P[2];
641
    unsigned int flags = 0;
642
    uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
643

    
644
    /* 2-color encoding for each 4x4 quadrant, or 2-color encoding on
645
     * either top and bottom or left and right halves */
646
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 4);
647

    
648
    P[0] = bytestream_get_le16(&s->stream_ptr);
649
    P[1] = bytestream_get_le16(&s->stream_ptr);
650

    
651
    if (!(P[0] & 0x8000)) {
652

    
653
        CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 24);
654
        s->stream_ptr -= 4;
655

    
656
        for (y = 0; y < 16; y++) {
657
            // new values for each 4x4 block
658
            if (!(y & 3)) {
659
                P[0] = bytestream_get_le16(&s->stream_ptr);
660
                P[1] = bytestream_get_le16(&s->stream_ptr);
661
                flags = bytestream_get_le16(&s->stream_ptr);
662
            }
663

    
664
            for (x = 0; x < 4; x++, flags >>= 1)
665
                *pixel_ptr++ = P[flags & 1];
666
            pixel_ptr += s->stride - 4;
667
            // switch to right half
668
            if (y == 7) pixel_ptr -= 8 * s->stride - 4;
669
        }
670

    
671
    } else {
672

    
673
        CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 12);
674

    
675
        if (!(AV_RL16(s->stream_ptr + 4) & 0x8000)) {
676

    
677
            flags = bytestream_get_le32(&s->stream_ptr);
678

    
679
            /* vertical split; left & right halves are 2-color encoded */
680

    
681
            for (y = 0; y < 16; y++) {
682
                for (x = 0; x < 4; x++, flags >>= 1)
683
                    *pixel_ptr++ = P[flags & 1];
684
                pixel_ptr += s->stride - 4;
685
                // switch to right half
686
                if (y == 7) {
687
                    pixel_ptr -= 8 * s->stride - 4;
688
                    P[0] = bytestream_get_le16(&s->stream_ptr);
689
                    P[1] = bytestream_get_le16(&s->stream_ptr);
690
                    flags = bytestream_get_le32(&s->stream_ptr);
691
                }
692
            }
693

    
694
        } else {
695

    
696
            /* horizontal split; top & bottom halves are 2-color encoded */
697

    
698
            for (y = 0; y < 8; y++) {
699
                if (y == 4) {
700
                    P[0] = bytestream_get_le16(&s->stream_ptr);
701
                    P[1] = bytestream_get_le16(&s->stream_ptr);
702
                }
703
                flags = *s->stream_ptr++ | 0x100;
704

    
705
                for (; flags != 1; flags >>= 1)
706
                    *pixel_ptr++ = P[flags & 1];
707
                pixel_ptr += s->line_inc;
708
            }
709
        }
710
    }
711

    
712
    /* report success */
713
    return 0;
714
}
715

    
716
static int ipvideo_decode_block_opcode_0x9_16(IpvideoContext *s)
717
{
718
    int x, y;
719
    uint16_t P[4];
720
    uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
721

    
722
    /* 4-color encoding */
723
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 8);
724

    
725
    for (x = 0; x < 4; x++)
726
        P[x] = bytestream_get_le16(&s->stream_ptr);
727

    
728
    if (!(P[0] & 0x8000)) {
729
        if (!(P[2] & 0x8000)) {
730

    
731
            /* 1 of 4 colors for each pixel */
732
            CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 16);
733

    
734
            for (y = 0; y < 8; y++) {
735
                /* get the next set of 8 2-bit flags */
736
                int flags = bytestream_get_le16(&s->stream_ptr);
737
                for (x = 0; x < 8; x++, flags >>= 2)
738
                    *pixel_ptr++ = P[flags & 0x03];
739
                pixel_ptr += s->line_inc;
740
            }
741

    
742
        } else {
743
            uint32_t flags;
744

    
745
            /* 1 of 4 colors for each 2x2 block */
746
            CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 4);
747

    
748
            flags = bytestream_get_le32(&s->stream_ptr);
749

    
750
            for (y = 0; y < 8; y += 2) {
751
                for (x = 0; x < 8; x += 2, flags >>= 2) {
752
                    pixel_ptr[x                ] =
753
                    pixel_ptr[x + 1            ] =
754
                    pixel_ptr[x +     s->stride] =
755
                    pixel_ptr[x + 1 + s->stride] = P[flags & 0x03];
756
                }
757
                pixel_ptr += s->stride * 2;
758
            }
759

    
760
        }
761
    } else {
762
        uint64_t flags;
763

    
764
        /* 1 of 4 colors for each 2x1 or 1x2 block */
765
        CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 8);
766

    
767
        flags = bytestream_get_le64(&s->stream_ptr);
768
        if (!(P[2] & 0x8000)) {
769
            for (y = 0; y < 8; y++) {
770
                for (x = 0; x < 8; x += 2, flags >>= 2) {
771
                    pixel_ptr[x    ] =
772
                    pixel_ptr[x + 1] = P[flags & 0x03];
773
                }
774
                pixel_ptr += s->stride;
775
            }
776
        } else {
777
            for (y = 0; y < 8; y += 2) {
778
                for (x = 0; x < 8; x++, flags >>= 2) {
779
                    pixel_ptr[x            ] =
780
                    pixel_ptr[x + s->stride] = P[flags & 0x03];
781
                }
782
                pixel_ptr += s->stride * 2;
783
            }
784
        }
785
    }
786

    
787
    /* report success */
788
    return 0;
789
}
790

    
791
static int ipvideo_decode_block_opcode_0xA_16(IpvideoContext *s)
792
{
793
    int x, y;
794
    uint16_t P[4];
795
    int flags = 0;
796
    uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
797

    
798
    /* 4-color encoding for each 4x4 quadrant, or 4-color encoding on
799
     * either top and bottom or left and right halves */
800
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 24);
801

    
802
    if (!(AV_RL16(s->stream_ptr) & 0x8000)) {
803

    
804
        /* 4-color encoding for each quadrant */
805
        CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 48);
806

    
807
        for (y = 0; y < 16; y++) {
808
            // new values for each 4x4 block
809
            if (!(y & 3)) {
810
                for (x = 0; x < 4; x++)
811
                    P[x] = bytestream_get_le16(&s->stream_ptr);
812
                flags = bytestream_get_le32(&s->stream_ptr);
813
            }
814

    
815
            for (x = 0; x < 4; x++, flags >>= 2)
816
                *pixel_ptr++ = P[flags & 0x03];
817

    
818
            pixel_ptr += s->stride - 4;
819
            // switch to right half
820
            if (y == 7) pixel_ptr -= 8 * s->stride - 4;
821
        }
822

    
823
    } else {
824
        // vertical split?
825
        int vert = !(AV_RL16(s->stream_ptr + 16) & 0x8000);
826
        uint64_t flags = 0;
827

    
828
        /* 4-color encoding for either left and right or top and bottom
829
         * halves */
830

    
831
        for (y = 0; y < 16; y++) {
832
            // load values for each half
833
            if (!(y & 7)) {
834
                for (x = 0; x < 4; x++)
835
                    P[x] = bytestream_get_le16(&s->stream_ptr);
836
                flags = bytestream_get_le64(&s->stream_ptr);
837
            }
838

    
839
            for (x = 0; x < 4; x++, flags >>= 2)
840
                *pixel_ptr++ = P[flags & 0x03];
841

    
842
            if (vert) {
843
                pixel_ptr += s->stride - 4;
844
                // switch to right half
845
                if (y == 7) pixel_ptr -= 8 * s->stride - 4;
846
            } else if (y & 1) pixel_ptr += s->line_inc;
847
        }
848
    }
849

    
850
    /* report success */
851
    return 0;
852
}
853

    
854
static int ipvideo_decode_block_opcode_0xB_16(IpvideoContext *s)
855
{
856
    int x, y;
857
    uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
858

    
859
    /* 64-color encoding (each pixel in block is a different color) */
860
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 128);
861

    
862
    for (y = 0; y < 8; y++) {
863
        for (x = 0; x < 8; x++)
864
            pixel_ptr[x] = bytestream_get_le16(&s->stream_ptr);
865
        pixel_ptr  += s->stride;
866
    }
867

    
868
    /* report success */
869
    return 0;
870
}
871

    
872
static int ipvideo_decode_block_opcode_0xC_16(IpvideoContext *s)
873
{
874
    int x, y;
875
    uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
876

    
877
    /* 16-color block encoding: each 2x2 block is a different color */
878
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 32);
879

    
880
    for (y = 0; y < 8; y += 2) {
881
        for (x = 0; x < 8; x += 2) {
882
            pixel_ptr[x                ] =
883
            pixel_ptr[x + 1            ] =
884
            pixel_ptr[x +     s->stride] =
885
            pixel_ptr[x + 1 + s->stride] = bytestream_get_le16(&s->stream_ptr);
886
        }
887
        pixel_ptr += s->stride * 2;
888
    }
889

    
890
    /* report success */
891
    return 0;
892
}
893

    
894
static int ipvideo_decode_block_opcode_0xD_16(IpvideoContext *s)
895
{
896
    int x, y;
897
    uint16_t P[2];
898
    uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
899

    
900
    /* 4-color block encoding: each 4x4 block is a different color */
901
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 8);
902

    
903
    for (y = 0; y < 8; y++) {
904
        if (!(y & 3)) {
905
            P[0] = bytestream_get_le16(&s->stream_ptr);
906
            P[1] = bytestream_get_le16(&s->stream_ptr);
907
        }
908
        for (x = 0; x < 8; x++)
909
            pixel_ptr[x] = P[x >> 2];
910
        pixel_ptr += s->stride;
911
    }
912

    
913
    /* report success */
914
    return 0;
915
}
916

    
917
static int ipvideo_decode_block_opcode_0xE_16(IpvideoContext *s)
918
{
919
    int x, y;
920
    uint16_t pix;
921
    uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
922

    
923
    /* 1-color encoding: the whole block is 1 solid color */
924
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2);
925
    pix = bytestream_get_le16(&s->stream_ptr);
926

    
927
    for (y = 0; y < 8; y++) {
928
        for (x = 0; x < 8; x++)
929
            pixel_ptr[x] = pix;
930
        pixel_ptr += s->stride;
931
    }
932

    
933
    /* report success */
934
    return 0;
935
}
936

    
937
static int (* const ipvideo_decode_block[])(IpvideoContext *s) = {
938
    ipvideo_decode_block_opcode_0x0, ipvideo_decode_block_opcode_0x1,
939
    ipvideo_decode_block_opcode_0x2, ipvideo_decode_block_opcode_0x3,
940
    ipvideo_decode_block_opcode_0x4, ipvideo_decode_block_opcode_0x5,
941
    ipvideo_decode_block_opcode_0x6, ipvideo_decode_block_opcode_0x7,
942
    ipvideo_decode_block_opcode_0x8, ipvideo_decode_block_opcode_0x9,
943
    ipvideo_decode_block_opcode_0xA, ipvideo_decode_block_opcode_0xB,
944
    ipvideo_decode_block_opcode_0xC, ipvideo_decode_block_opcode_0xD,
945
    ipvideo_decode_block_opcode_0xE, ipvideo_decode_block_opcode_0xF,
946
};
947

    
948
static int (* const ipvideo_decode_block16[])(IpvideoContext *s) = {
949
    ipvideo_decode_block_opcode_0x0,    ipvideo_decode_block_opcode_0x1,
950
    ipvideo_decode_block_opcode_0x2,    ipvideo_decode_block_opcode_0x3,
951
    ipvideo_decode_block_opcode_0x4,    ipvideo_decode_block_opcode_0x5,
952
    ipvideo_decode_block_opcode_0x6_16, ipvideo_decode_block_opcode_0x7_16,
953
    ipvideo_decode_block_opcode_0x8_16, ipvideo_decode_block_opcode_0x9_16,
954
    ipvideo_decode_block_opcode_0xA_16, ipvideo_decode_block_opcode_0xB_16,
955
    ipvideo_decode_block_opcode_0xC_16, ipvideo_decode_block_opcode_0xD_16,
956
    ipvideo_decode_block_opcode_0xE_16, ipvideo_decode_block_opcode_0x1,
957
};
958

    
959
static void ipvideo_decode_opcodes(IpvideoContext *s)
960
{
961
    int x, y;
962
    unsigned char opcode;
963
    int ret;
964
    static int frame = 0;
965
    GetBitContext gb;
966

    
967
    debug_interplay("------------------ frame %d\n", frame);
968
    frame++;
969

    
970
    if (!s->is_16bpp) {
971
        /* this is PAL8, so make the palette available */
972
        memcpy(s->current_frame.data[1], s->avctx->palctrl->palette, PALETTE_COUNT * 4);
973

    
974
        s->stride = s->current_frame.linesize[0];
975
        s->stream_ptr = s->buf + 14;  /* data starts 14 bytes in */
976
        s->stream_end = s->buf + s->size;
977
    } else {
978
        s->stride = s->current_frame.linesize[0] >> 1;
979
        s->stream_ptr = s->buf + 16;
980
        s->stream_end =
981
        s->mv_ptr = s->buf + 14 + AV_RL16(s->buf+14);
982
        s->mv_end = s->buf + s->size;
983
    }
984
    s->line_inc = s->stride - 8;
985
    s->upper_motion_limit_offset = (s->avctx->height - 8) * s->current_frame.linesize[0]
986
                                  + (s->avctx->width - 8) * (1 + s->is_16bpp);
987

    
988
    init_get_bits(&gb, s->decoding_map, s->decoding_map_size * 8);
989
    for (y = 0; y < s->avctx->height; y += 8) {
990
        for (x = 0; x < s->avctx->width; x += 8) {
991
            opcode = get_bits(&gb, 4);
992

    
993
            debug_interplay("  block @ (%3d, %3d): encoding 0x%X, data ptr @ %p\n",
994
                            x, y, opcode, s->stream_ptr);
995

    
996
            if (!s->is_16bpp) {
997
                s->pixel_ptr = s->current_frame.data[0] + x
998
                              + y*s->current_frame.linesize[0];
999
                ret = ipvideo_decode_block[opcode](s);
1000
            } else {
1001
                s->pixel_ptr = s->current_frame.data[0] + x*2
1002
                              + y*s->current_frame.linesize[0];
1003
                ret = ipvideo_decode_block16[opcode](s);
1004
            }
1005
            if (ret != 0) {
1006
                av_log(s->avctx, AV_LOG_ERROR, " Interplay video: decode problem on frame %d, @ block (%d, %d)\n",
1007
                       frame, x, y);
1008
                return;
1009
            }
1010
        }
1011
    }
1012
    if (s->stream_end - s->stream_ptr > 1) {
1013
        av_log(s->avctx, AV_LOG_ERROR, " Interplay video: decode finished with %td bytes left over\n",
1014
               s->stream_end - s->stream_ptr);
1015
    }
1016
}
1017

    
1018
static av_cold int ipvideo_decode_init(AVCodecContext *avctx)
1019
{
1020
    IpvideoContext *s = avctx->priv_data;
1021

    
1022
    s->avctx = avctx;
1023

    
1024
    s->is_16bpp = avctx->bits_per_coded_sample == 16;
1025
    avctx->pix_fmt = s->is_16bpp ? PIX_FMT_RGB555 : PIX_FMT_PAL8;
1026
    if (!s->is_16bpp && s->avctx->palctrl == NULL) {
1027
        av_log(avctx, AV_LOG_ERROR, " Interplay video: palette expected.\n");
1028
        return -1;
1029
    }
1030

    
1031
    dsputil_init(&s->dsp, avctx);
1032

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

    
1036
    s->current_frame.data[0] = s->last_frame.data[0] =
1037
    s->second_last_frame.data[0] = NULL;
1038

    
1039
    return 0;
1040
}
1041

    
1042
static int ipvideo_decode_frame(AVCodecContext *avctx,
1043
                                void *data, int *data_size,
1044
                                AVPacket *avpkt)
1045
{
1046
    const uint8_t *buf = avpkt->data;
1047
    int buf_size = avpkt->size;
1048
    IpvideoContext *s = avctx->priv_data;
1049
    AVPaletteControl *palette_control = avctx->palctrl;
1050

    
1051
    /* compressed buffer needs to be large enough to at least hold an entire
1052
     * decoding map */
1053
    if (buf_size < s->decoding_map_size)
1054
        return buf_size;
1055

    
1056
    s->decoding_map = buf;
1057
    s->buf = buf + s->decoding_map_size;
1058
    s->size = buf_size - s->decoding_map_size;
1059

    
1060
    s->current_frame.reference = 3;
1061
    if (avctx->get_buffer(avctx, &s->current_frame)) {
1062
        av_log(avctx, AV_LOG_ERROR, "  Interplay Video: get_buffer() failed\n");
1063
        return -1;
1064
    }
1065

    
1066
    ipvideo_decode_opcodes(s);
1067

    
1068
    if (!s->is_16bpp && palette_control->palette_changed) {
1069
        palette_control->palette_changed = 0;
1070
        s->current_frame.palette_has_changed = 1;
1071
    }
1072

    
1073
    *data_size = sizeof(AVFrame);
1074
    *(AVFrame*)data = s->current_frame;
1075

    
1076
    /* shuffle frames */
1077
    if (s->second_last_frame.data[0])
1078
        avctx->release_buffer(avctx, &s->second_last_frame);
1079
    s->second_last_frame = s->last_frame;
1080
    s->last_frame = s->current_frame;
1081
    s->current_frame.data[0] = NULL;  /* catch any access attempts */
1082

    
1083
    /* report that the buffer was completely consumed */
1084
    return buf_size;
1085
}
1086

    
1087
static av_cold int ipvideo_decode_end(AVCodecContext *avctx)
1088
{
1089
    IpvideoContext *s = avctx->priv_data;
1090

    
1091
    /* release the last frame */
1092
    if (s->last_frame.data[0])
1093
        avctx->release_buffer(avctx, &s->last_frame);
1094
    if (s->second_last_frame.data[0])
1095
        avctx->release_buffer(avctx, &s->second_last_frame);
1096

    
1097
    return 0;
1098
}
1099

    
1100
AVCodec interplay_video_decoder = {
1101
    "interplayvideo",
1102
    AVMEDIA_TYPE_VIDEO,
1103
    CODEC_ID_INTERPLAY_VIDEO,
1104
    sizeof(IpvideoContext),
1105
    ipvideo_decode_init,
1106
    NULL,
1107
    ipvideo_decode_end,
1108
    ipvideo_decode_frame,
1109
    CODEC_CAP_DR1,
1110
    .long_name = NULL_IF_CONFIG_SMALL("Interplay MVE video"),
1111
};