Statistics
| Branch: | Revision:

ffmpeg / libavcodec / interplayvideo.c @ 72415b2a

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

    
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
    s->dsp.put_pixels_tab[!s->is_16bpp][0](s->pixel_ptr, src->data[0] + motion_offset,
103
                                           s->current_frame.linesize[0], 8);
104
    return 0;
105
}
106

    
107
static int ipvideo_decode_block_opcode_0x0(IpvideoContext *s)
108
{
109
    return copy_from(s, &s->last_frame, 0, 0);
110
}
111

    
112
static int ipvideo_decode_block_opcode_0x1(IpvideoContext *s)
113
{
114
    return copy_from(s, &s->second_last_frame, 0, 0);
115
}
116

    
117
static int ipvideo_decode_block_opcode_0x2(IpvideoContext *s)
118
{
119
    unsigned char B;
120
    int x, y;
121

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

    
131
    if (B < 56) {
132
        x = 8 + (B % 7);
133
        y = B / 7;
134
    } else {
135
        x = -14 + ((B - 56) % 29);
136
        y =   8 + ((B - 56) / 29);
137
    }
138

    
139
    debug_interplay ("    motion byte = %d, (x, y) = (%d, %d)\n", B, x, y);
140
    return copy_from(s, &s->second_last_frame, x, y);
141
}
142

    
143
static int ipvideo_decode_block_opcode_0x3(IpvideoContext *s)
144
{
145
    unsigned char B;
146
    int x, y;
147

    
148
    /* copy 8x8 block from current frame from an up/left block */
149

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

    
159
    if (B < 56) {
160
        x = -(8 + (B % 7));
161
        y = -(B / 7);
162
    } else {
163
        x = -(-14 + ((B - 56) % 29));
164
        y = -(  8 + ((B - 56) / 29));
165
    }
166

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

    
171
static int ipvideo_decode_block_opcode_0x4(IpvideoContext *s)
172
{
173
    int x, y;
174
    unsigned char B, BL, BH;
175

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

    
185
    BL = B & 0x0F;
186
    BH = (B >> 4) & 0x0F;
187
    x = -8 + BL;
188
    y = -8 + BH;
189

    
190
    debug_interplay ("    motion byte = %d, (x, y) = (%d, %d)\n", B, x, y);
191
    return copy_from(s, &s->last_frame, x, y);
192
}
193

    
194
static int ipvideo_decode_block_opcode_0x5(IpvideoContext *s)
195
{
196
    signed char x, y;
197

    
198
    /* copy a block from the previous frame using an expanded range;
199
     * need 2 more bytes */
200
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2);
201

    
202
    x = *s->stream_ptr++;
203
    y = *s->stream_ptr++;
204

    
205
    debug_interplay ("    motion bytes = %d, %d\n", x, y);
206
    return copy_from(s, &s->last_frame, x, y);
207
}
208

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

    
214
    /* report success */
215
    return 0;
216
}
217

    
218
static int ipvideo_decode_block_opcode_0x7(IpvideoContext *s)
219
{
220
    int x, y;
221
    unsigned char P[2];
222
    unsigned int flags;
223

    
224
    /* 2-color encoding */
225
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2);
226

    
227
    P[0] = *s->stream_ptr++;
228
    P[1] = *s->stream_ptr++;
229

    
230
    if (P[0] <= P[1]) {
231

    
232
        /* need 8 more bytes from the stream */
233
        CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 8);
234

    
235
        for (y = 0; y < 8; y++) {
236
            flags = *s->stream_ptr++ | 0x100;
237
            for (; flags != 1; flags >>= 1)
238
                *s->pixel_ptr++ = P[flags & 1];
239
            s->pixel_ptr += s->line_inc;
240
        }
241

    
242
    } else {
243

    
244
        /* need 2 more bytes from the stream */
245
        CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2);
246

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

    
259
    /* report success */
260
    return 0;
261
}
262

    
263
static int ipvideo_decode_block_opcode_0x8(IpvideoContext *s)
264
{
265
    int x, y;
266
    unsigned char P[2];
267
    unsigned int flags = 0;
268

    
269
    /* 2-color encoding for each 4x4 quadrant, or 2-color encoding on
270
     * either top and bottom or left and right halves */
271
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2);
272

    
273
    P[0] = *s->stream_ptr++;
274
    P[1] = *s->stream_ptr++;
275

    
276
    if (P[0] <= P[1]) {
277

    
278
        CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 14);
279
        s->stream_ptr -= 2;
280

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

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

    
295
    } else {
296

    
297
        /* need 10 more bytes */
298
        CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 10);
299

    
300
        if (s->stream_ptr[4] <= s->stream_ptr[5]) {
301

    
302
            flags = bytestream_get_le32(&s->stream_ptr);
303

    
304
            /* vertical split; left & right halves are 2-color encoded */
305

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

    
318
        } else {
319

    
320
            /* horizontal split; top & bottom halves are 2-color encoded */
321

    
322
            for (y = 0; y < 8; y++) {
323
                if (y == 4) {
324
                    P[0] = *s->stream_ptr++;
325
                    P[1] = *s->stream_ptr++;
326
                }
327
                flags = *s->stream_ptr++ | 0x100;
328

    
329
                for (; flags != 1; flags >>= 1)
330
                    *s->pixel_ptr++ = P[flags & 1];
331
                s->pixel_ptr += s->line_inc;
332
            }
333
        }
334
    }
335

    
336
    /* report success */
337
    return 0;
338
}
339

    
340
static int ipvideo_decode_block_opcode_0x9(IpvideoContext *s)
341
{
342
    int x, y;
343
    unsigned char P[4];
344

    
345
    /* 4-color encoding */
346
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 4);
347

    
348
    memcpy(P, s->stream_ptr, 4);
349
    s->stream_ptr += 4;
350

    
351
    if (P[0] <= P[1]) {
352
        if (P[2] <= P[3]) {
353

    
354
            /* 1 of 4 colors for each pixel, need 16 more bytes */
355
            CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 16);
356

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

    
365
        } else {
366
            uint32_t flags;
367

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

    
371
            flags = bytestream_get_le32(&s->stream_ptr);
372

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

    
383
        }
384
    } else {
385
        uint64_t flags;
386

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

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

    
410
    /* report success */
411
    return 0;
412
}
413

    
414
static int ipvideo_decode_block_opcode_0xA(IpvideoContext *s)
415
{
416
    int x, y;
417
    unsigned char P[4];
418
    int flags = 0;
419

    
420
    /* 4-color encoding for each 4x4 quadrant, or 4-color encoding on
421
     * either top and bottom or left and right halves */
422
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 24);
423

    
424
    if (s->stream_ptr[0] <= s->stream_ptr[1]) {
425

    
426
        /* 4-color encoding for each quadrant; need 32 bytes */
427
        CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 32);
428

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

    
437
            for (x = 0; x < 4; x++, flags >>= 2)
438
                *s->pixel_ptr++ = P[flags & 0x03];
439

    
440
            s->pixel_ptr += s->stride - 4;
441
            // switch to right half
442
            if (y == 7) s->pixel_ptr -= 8 * s->stride - 4;
443
        }
444

    
445
    } else {
446
        // vertical split?
447
        int vert = s->stream_ptr[12] <= s->stream_ptr[13];
448
        uint64_t flags = 0;
449

    
450
        /* 4-color encoding for either left and right or top and bottom
451
         * halves */
452

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

    
461
            for (x = 0; x < 4; x++, flags >>= 2)
462
                *s->pixel_ptr++ = P[flags & 0x03];
463

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

    
472
    /* report success */
473
    return 0;
474
}
475

    
476
static int ipvideo_decode_block_opcode_0xB(IpvideoContext *s)
477
{
478
    int y;
479

    
480
    /* 64-color encoding (each pixel in block is a different color) */
481
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 64);
482

    
483
    for (y = 0; y < 8; y++) {
484
        memcpy(s->pixel_ptr, s->stream_ptr, 8);
485
        s->stream_ptr += 8;
486
        s->pixel_ptr  += s->stride;
487
    }
488

    
489
    /* report success */
490
    return 0;
491
}
492

    
493
static int ipvideo_decode_block_opcode_0xC(IpvideoContext *s)
494
{
495
    int x, y;
496

    
497
    /* 16-color block encoding: each 2x2 block is a different color */
498
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 16);
499

    
500
    for (y = 0; y < 8; y += 2) {
501
        for (x = 0; x < 8; x += 2) {
502
            s->pixel_ptr[x                ] =
503
            s->pixel_ptr[x + 1            ] =
504
            s->pixel_ptr[x +     s->stride] =
505
            s->pixel_ptr[x + 1 + s->stride] = *s->stream_ptr++;
506
        }
507
        s->pixel_ptr += s->stride * 2;
508
    }
509

    
510
    /* report success */
511
    return 0;
512
}
513

    
514
static int ipvideo_decode_block_opcode_0xD(IpvideoContext *s)
515
{
516
    int y;
517
    unsigned char P[2];
518

    
519
    /* 4-color block encoding: each 4x4 block is a different color */
520
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 4);
521

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

    
532
    /* report success */
533
    return 0;
534
}
535

    
536
static int ipvideo_decode_block_opcode_0xE(IpvideoContext *s)
537
{
538
    int y;
539
    unsigned char pix;
540

    
541
    /* 1-color encoding: the whole block is 1 solid color */
542
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 1);
543
    pix = *s->stream_ptr++;
544

    
545
    for (y = 0; y < 8; y++) {
546
        memset(s->pixel_ptr, pix, 8);
547
        s->pixel_ptr += s->stride;
548
    }
549

    
550
    /* report success */
551
    return 0;
552
}
553

    
554
static int ipvideo_decode_block_opcode_0xF(IpvideoContext *s)
555
{
556
    int x, y;
557
    unsigned char sample[2];
558

    
559
    /* dithered encoding */
560
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2);
561
    sample[0] = *s->stream_ptr++;
562
    sample[1] = *s->stream_ptr++;
563

    
564
    for (y = 0; y < 8; y++) {
565
        for (x = 0; x < 8; x += 2) {
566
            *s->pixel_ptr++ = sample[  y & 1 ];
567
            *s->pixel_ptr++ = sample[!(y & 1)];
568
        }
569
        s->pixel_ptr += s->line_inc;
570
    }
571

    
572
    /* report success */
573
    return 0;
574
}
575

    
576
static int ipvideo_decode_block_opcode_0x6_16(IpvideoContext *s)
577
{
578
    signed char x, y;
579

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

    
583
    x = *s->stream_ptr++;
584
    y = *s->stream_ptr++;
585

    
586
    debug_interplay ("    motion bytes = %d, %d\n", x, y);
587
    return copy_from(s, &s->second_last_frame, x, y);
588
}
589

    
590
static int ipvideo_decode_block_opcode_0x7_16(IpvideoContext *s)
591
{
592
    int x, y;
593
    uint16_t P[2];
594
    unsigned int flags;
595
    uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
596

    
597
    /* 2-color encoding */
598
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 4);
599

    
600
    P[0] = bytestream_get_le16(&s->stream_ptr);
601
    P[1] = bytestream_get_le16(&s->stream_ptr);
602

    
603
    if (!(P[0] & 0x8000)) {
604

    
605
        CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 8);
606

    
607
        for (y = 0; y < 8; y++) {
608
            flags = *s->stream_ptr++ | 0x100;
609
            for (; flags != 1; flags >>= 1)
610
                *pixel_ptr++ = P[flags & 1];
611
            pixel_ptr += s->line_inc;
612
        }
613

    
614
    } else {
615

    
616
        CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2);
617

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

    
630
    return 0;
631
}
632

    
633
static int ipvideo_decode_block_opcode_0x8_16(IpvideoContext *s)
634
{
635
    int x, y;
636
    uint16_t P[2];
637
    unsigned int flags = 0;
638
    uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
639

    
640
    /* 2-color encoding for each 4x4 quadrant, or 2-color encoding on
641
     * either top and bottom or left and right halves */
642
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 4);
643

    
644
    P[0] = bytestream_get_le16(&s->stream_ptr);
645
    P[1] = bytestream_get_le16(&s->stream_ptr);
646

    
647
    if (!(P[0] & 0x8000)) {
648

    
649
        CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 24);
650
        s->stream_ptr -= 4;
651

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

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

    
667
    } else {
668

    
669
        CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 12);
670

    
671
        if (!(AV_RL16(s->stream_ptr + 4) & 0x8000)) {
672

    
673
            flags = bytestream_get_le32(&s->stream_ptr);
674

    
675
            /* vertical split; left & right halves are 2-color encoded */
676

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

    
690
        } else {
691

    
692
            /* horizontal split; top & bottom halves are 2-color encoded */
693

    
694
            for (y = 0; y < 8; y++) {
695
                if (y == 4) {
696
                    P[0] = bytestream_get_le16(&s->stream_ptr);
697
                    P[1] = bytestream_get_le16(&s->stream_ptr);
698
                }
699
                flags = *s->stream_ptr++ | 0x100;
700

    
701
                for (; flags != 1; flags >>= 1)
702
                    *pixel_ptr++ = P[flags & 1];
703
                pixel_ptr += s->line_inc;
704
            }
705
        }
706
    }
707

    
708
    /* report success */
709
    return 0;
710
}
711

    
712
static int ipvideo_decode_block_opcode_0x9_16(IpvideoContext *s)
713
{
714
    int x, y;
715
    uint16_t P[4];
716
    uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
717

    
718
    /* 4-color encoding */
719
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 8);
720

    
721
    for (x = 0; x < 4; x++)
722
        P[x] = bytestream_get_le16(&s->stream_ptr);
723

    
724
    if (!(P[0] & 0x8000)) {
725
        if (!(P[2] & 0x8000)) {
726

    
727
            /* 1 of 4 colors for each pixel */
728
            CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 16);
729

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

    
738
        } else {
739
            uint32_t flags;
740

    
741
            /* 1 of 4 colors for each 2x2 block */
742
            CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 4);
743

    
744
            flags = bytestream_get_le32(&s->stream_ptr);
745

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

    
756
        }
757
    } else {
758
        uint64_t flags;
759

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

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

    
783
    /* report success */
784
    return 0;
785
}
786

    
787
static int ipvideo_decode_block_opcode_0xA_16(IpvideoContext *s)
788
{
789
    int x, y;
790
    uint16_t P[4];
791
    int flags = 0;
792
    uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
793

    
794
    /* 4-color encoding for each 4x4 quadrant, or 4-color encoding on
795
     * either top and bottom or left and right halves */
796
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 24);
797

    
798
    if (!(AV_RL16(s->stream_ptr) & 0x8000)) {
799

    
800
        /* 4-color encoding for each quadrant */
801
        CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 48);
802

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

    
811
            for (x = 0; x < 4; x++, flags >>= 2)
812
                *pixel_ptr++ = P[flags & 0x03];
813

    
814
            pixel_ptr += s->stride - 4;
815
            // switch to right half
816
            if (y == 7) pixel_ptr -= 8 * s->stride - 4;
817
        }
818

    
819
    } else {
820
        // vertical split?
821
        int vert = !(AV_RL16(s->stream_ptr + 16) & 0x8000);
822
        uint64_t flags = 0;
823

    
824
        /* 4-color encoding for either left and right or top and bottom
825
         * halves */
826

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

    
835
            for (x = 0; x < 4; x++, flags >>= 2)
836
                *pixel_ptr++ = P[flags & 0x03];
837

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

    
846
    /* report success */
847
    return 0;
848
}
849

    
850
static int ipvideo_decode_block_opcode_0xB_16(IpvideoContext *s)
851
{
852
    int x, y;
853
    uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
854

    
855
    /* 64-color encoding (each pixel in block is a different color) */
856
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 128);
857

    
858
    for (y = 0; y < 8; y++) {
859
        for (x = 0; x < 8; x++)
860
            pixel_ptr[x] = bytestream_get_le16(&s->stream_ptr);
861
        pixel_ptr  += s->stride;
862
    }
863

    
864
    /* report success */
865
    return 0;
866
}
867

    
868
static int ipvideo_decode_block_opcode_0xC_16(IpvideoContext *s)
869
{
870
    int x, y;
871
    uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
872

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

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

    
886
    /* report success */
887
    return 0;
888
}
889

    
890
static int ipvideo_decode_block_opcode_0xD_16(IpvideoContext *s)
891
{
892
    int x, y;
893
    uint16_t P[2];
894
    uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
895

    
896
    /* 4-color block encoding: each 4x4 block is a different color */
897
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 8);
898

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

    
909
    /* report success */
910
    return 0;
911
}
912

    
913
static int ipvideo_decode_block_opcode_0xE_16(IpvideoContext *s)
914
{
915
    int x, y;
916
    uint16_t pix;
917
    uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
918

    
919
    /* 1-color encoding: the whole block is 1 solid color */
920
    CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2);
921
    pix = bytestream_get_le16(&s->stream_ptr);
922

    
923
    for (y = 0; y < 8; y++) {
924
        for (x = 0; x < 8; x++)
925
            pixel_ptr[x] = pix;
926
        pixel_ptr += s->stride;
927
    }
928

    
929
    /* report success */
930
    return 0;
931
}
932

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

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

    
955
static void ipvideo_decode_opcodes(IpvideoContext *s)
956
{
957
    int x, y;
958
    unsigned char opcode;
959
    int ret;
960
    static int frame = 0;
961
    GetBitContext gb;
962

    
963
    debug_interplay("------------------ frame %d\n", frame);
964
    frame++;
965

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

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

    
984
    init_get_bits(&gb, s->decoding_map, s->decoding_map_size * 8);
985
    for (y = 0; y < s->avctx->height; y += 8) {
986
        for (x = 0; x < s->avctx->width; x += 8) {
987
            opcode = get_bits(&gb, 4);
988

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

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

    
1014
static av_cold int ipvideo_decode_init(AVCodecContext *avctx)
1015
{
1016
    IpvideoContext *s = avctx->priv_data;
1017

    
1018
    s->avctx = avctx;
1019

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

    
1027
    dsputil_init(&s->dsp, avctx);
1028

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

    
1032
    s->current_frame.data[0] = s->last_frame.data[0] =
1033
    s->second_last_frame.data[0] = NULL;
1034

    
1035
    return 0;
1036
}
1037

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

    
1047
    /* compressed buffer needs to be large enough to at least hold an entire
1048
     * decoding map */
1049
    if (buf_size < s->decoding_map_size)
1050
        return buf_size;
1051

    
1052
    s->decoding_map = buf;
1053
    s->buf = buf + s->decoding_map_size;
1054
    s->size = buf_size - s->decoding_map_size;
1055

    
1056
    s->current_frame.reference = 3;
1057
    if (avctx->get_buffer(avctx, &s->current_frame)) {
1058
        av_log(avctx, AV_LOG_ERROR, "  Interplay Video: get_buffer() failed\n");
1059
        return -1;
1060
    }
1061

    
1062
    ipvideo_decode_opcodes(s);
1063

    
1064
    if (!s->is_16bpp && palette_control->palette_changed) {
1065
        palette_control->palette_changed = 0;
1066
        s->current_frame.palette_has_changed = 1;
1067
    }
1068

    
1069
    *data_size = sizeof(AVFrame);
1070
    *(AVFrame*)data = s->current_frame;
1071

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

    
1079
    /* report that the buffer was completely consumed */
1080
    return buf_size;
1081
}
1082

    
1083
static av_cold int ipvideo_decode_end(AVCodecContext *avctx)
1084
{
1085
    IpvideoContext *s = avctx->priv_data;
1086

    
1087
    /* release the last frame */
1088
    if (s->last_frame.data[0])
1089
        avctx->release_buffer(avctx, &s->last_frame);
1090
    if (s->second_last_frame.data[0])
1091
        avctx->release_buffer(avctx, &s->second_last_frame);
1092

    
1093
    return 0;
1094
}
1095

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