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
54static inline void debug_interplay(const char *format, ...) { }
55#endif
56
57typedef 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
89static 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
107static int ipvideo_decode_block_opcode_0x0(IpvideoContext *s)
108{
109    return copy_from(s, &s->last_frame, 0, 0);
110}
111
112static int ipvideo_decode_block_opcode_0x1(IpvideoContext *s)
113{
114    return copy_from(s, &s->second_last_frame, 0, 0);
115}
116
117static 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
143static 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
171static 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
194static 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
209static 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
218static 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
263static 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
340static 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
414static 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
476static 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
493static 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
514static 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
536static 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
554static 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
576static 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
590static 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
633static 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
712static 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
787static 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
850static 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
868static 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
890static 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
913static 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
933static 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
944static 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
955static 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
1014static 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
1038static 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
1083static 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
1096AVCodec 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};
1108