2 * Interplay MVE Video Decoder
3 * Copyright (C) 2003 the ffmpeg project
5 * This file is part of FFmpeg.
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.
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.
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
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.
30 * This decoder presently only supports a PAL8 output colorspace.
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.
42 #include "bytestream.h"
44 #define BITSTREAM_READER_LE
47 #define PALETTE_COUNT 256
49 typedef struct IpvideoContext {
51 AVCodecContext *avctx;
53 AVFrame second_last_frame;
55 AVFrame current_frame;
56 const unsigned char *decoding_map;
57 int decoding_map_size;
59 const unsigned char *buf;
63 const unsigned char *stream_ptr;
64 const unsigned char *stream_end;
65 const uint8_t *mv_ptr;
66 const uint8_t *mv_end;
67 unsigned char *pixel_ptr;
70 int upper_motion_limit_offset;
75 #define CHECK_STREAM_PTR(stream_ptr, stream_end, n) \
76 if (stream_end - stream_ptr < n) { \
77 av_log(s->avctx, AV_LOG_ERROR, "Interplay video warning: stream_ptr out of bounds (%p >= %p)\n", \
78 stream_ptr + n, stream_end); \
82 static int copy_from(IpvideoContext *s, AVFrame *src, int delta_x, int delta_y)
84 int current_offset = s->pixel_ptr - s->current_frame.data[0];
85 int motion_offset = current_offset + delta_y * s->current_frame.linesize[0]
86 + delta_x * (1 + s->is_16bpp);
87 if (motion_offset < 0) {
88 av_log(s->avctx, AV_LOG_ERROR, " Interplay video: motion offset < 0 (%d)\n", motion_offset);
90 } else if (motion_offset > s->upper_motion_limit_offset) {
91 av_log(s->avctx, AV_LOG_ERROR, " Interplay video: motion offset above limit (%d >= %d)\n",
92 motion_offset, s->upper_motion_limit_offset);
95 if (src->data[0] == NULL) {
96 av_log(s->avctx, AV_LOG_ERROR, "Invalid decode type, corrupted header?\n");
97 return AVERROR(EINVAL);
99 s->dsp.put_pixels_tab[!s->is_16bpp][0](s->pixel_ptr, src->data[0] + motion_offset,
100 s->current_frame.linesize[0], 8);
104 static int ipvideo_decode_block_opcode_0x0(IpvideoContext *s)
106 return copy_from(s, &s->last_frame, 0, 0);
109 static int ipvideo_decode_block_opcode_0x1(IpvideoContext *s)
111 return copy_from(s, &s->second_last_frame, 0, 0);
114 static int ipvideo_decode_block_opcode_0x2(IpvideoContext *s)
119 /* copy block from 2 frames ago using a motion vector; need 1 more byte */
121 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 1);
122 B = *s->stream_ptr++;
124 CHECK_STREAM_PTR(s->mv_ptr, s->mv_end, 1);
132 x = -14 + ((B - 56) % 29);
133 y = 8 + ((B - 56) / 29);
136 av_dlog(NULL, " motion byte = %d, (x, y) = (%d, %d)\n", B, x, y);
137 return copy_from(s, &s->second_last_frame, x, y);
140 static int ipvideo_decode_block_opcode_0x3(IpvideoContext *s)
145 /* copy 8x8 block from current frame from an up/left block */
147 /* need 1 more byte for motion */
149 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 1);
150 B = *s->stream_ptr++;
152 CHECK_STREAM_PTR(s->mv_ptr, s->mv_end, 1);
160 x = -(-14 + ((B - 56) % 29));
161 y = -( 8 + ((B - 56) / 29));
164 av_dlog(NULL, " motion byte = %d, (x, y) = (%d, %d)\n", B, x, y);
165 return copy_from(s, &s->current_frame, x, y);
168 static int ipvideo_decode_block_opcode_0x4(IpvideoContext *s)
171 unsigned char B, BL, BH;
173 /* copy a block from the previous frame; need 1 more byte */
175 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 1);
176 B = *s->stream_ptr++;
178 CHECK_STREAM_PTR(s->mv_ptr, s->mv_end, 1);
183 BH = (B >> 4) & 0x0F;
187 av_dlog(NULL, " motion byte = %d, (x, y) = (%d, %d)\n", B, x, y);
188 return copy_from(s, &s->last_frame, x, y);
191 static int ipvideo_decode_block_opcode_0x5(IpvideoContext *s)
195 /* copy a block from the previous frame using an expanded range;
196 * need 2 more bytes */
197 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2);
199 x = *s->stream_ptr++;
200 y = *s->stream_ptr++;
202 av_dlog(NULL, " motion bytes = %d, %d\n", x, y);
203 return copy_from(s, &s->last_frame, x, y);
206 static int ipvideo_decode_block_opcode_0x6(IpvideoContext *s)
208 /* mystery opcode? skip multiple blocks? */
209 av_log(s->avctx, AV_LOG_ERROR, " Interplay video: Help! Mystery opcode 0x6 seen\n");
215 static int ipvideo_decode_block_opcode_0x7(IpvideoContext *s)
221 /* 2-color encoding */
222 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2);
224 P[0] = *s->stream_ptr++;
225 P[1] = *s->stream_ptr++;
229 /* need 8 more bytes from the stream */
230 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 8);
232 for (y = 0; y < 8; y++) {
233 flags = *s->stream_ptr++ | 0x100;
234 for (; flags != 1; flags >>= 1)
235 *s->pixel_ptr++ = P[flags & 1];
236 s->pixel_ptr += s->line_inc;
241 /* need 2 more bytes from the stream */
242 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2);
244 flags = bytestream_get_le16(&s->stream_ptr);
245 for (y = 0; y < 8; y += 2) {
246 for (x = 0; x < 8; x += 2, flags >>= 1) {
248 s->pixel_ptr[x + 1 ] =
249 s->pixel_ptr[x + s->stride] =
250 s->pixel_ptr[x + 1 + s->stride] = P[flags & 1];
252 s->pixel_ptr += s->stride * 2;
260 static int ipvideo_decode_block_opcode_0x8(IpvideoContext *s)
264 unsigned int flags = 0;
266 /* 2-color encoding for each 4x4 quadrant, or 2-color encoding on
267 * either top and bottom or left and right halves */
268 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2);
270 P[0] = *s->stream_ptr++;
271 P[1] = *s->stream_ptr++;
275 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 14);
278 for (y = 0; y < 16; y++) {
279 // new values for each 4x4 block
281 P[0] = *s->stream_ptr++; P[1] = *s->stream_ptr++;
282 flags = bytestream_get_le16(&s->stream_ptr);
285 for (x = 0; x < 4; x++, flags >>= 1)
286 *s->pixel_ptr++ = P[flags & 1];
287 s->pixel_ptr += s->stride - 4;
288 // switch to right half
289 if (y == 7) s->pixel_ptr -= 8 * s->stride - 4;
294 /* need 10 more bytes */
295 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 10);
297 if (s->stream_ptr[4] <= s->stream_ptr[5]) {
299 flags = bytestream_get_le32(&s->stream_ptr);
301 /* vertical split; left & right halves are 2-color encoded */
303 for (y = 0; y < 16; y++) {
304 for (x = 0; x < 4; x++, flags >>= 1)
305 *s->pixel_ptr++ = P[flags & 1];
306 s->pixel_ptr += s->stride - 4;
307 // switch to right half
309 s->pixel_ptr -= 8 * s->stride - 4;
310 P[0] = *s->stream_ptr++; P[1] = *s->stream_ptr++;
311 flags = bytestream_get_le32(&s->stream_ptr);
317 /* horizontal split; top & bottom halves are 2-color encoded */
319 for (y = 0; y < 8; y++) {
321 P[0] = *s->stream_ptr++;
322 P[1] = *s->stream_ptr++;
324 flags = *s->stream_ptr++ | 0x100;
326 for (; flags != 1; flags >>= 1)
327 *s->pixel_ptr++ = P[flags & 1];
328 s->pixel_ptr += s->line_inc;
337 static int ipvideo_decode_block_opcode_0x9(IpvideoContext *s)
342 /* 4-color encoding */
343 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 4);
345 memcpy(P, s->stream_ptr, 4);
351 /* 1 of 4 colors for each pixel, need 16 more bytes */
352 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 16);
354 for (y = 0; y < 8; y++) {
355 /* get the next set of 8 2-bit flags */
356 int flags = bytestream_get_le16(&s->stream_ptr);
357 for (x = 0; x < 8; x++, flags >>= 2)
358 *s->pixel_ptr++ = P[flags & 0x03];
359 s->pixel_ptr += s->line_inc;
365 /* 1 of 4 colors for each 2x2 block, need 4 more bytes */
366 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 4);
368 flags = bytestream_get_le32(&s->stream_ptr);
370 for (y = 0; y < 8; y += 2) {
371 for (x = 0; x < 8; x += 2, flags >>= 2) {
373 s->pixel_ptr[x + 1 ] =
374 s->pixel_ptr[x + s->stride] =
375 s->pixel_ptr[x + 1 + s->stride] = P[flags & 0x03];
377 s->pixel_ptr += s->stride * 2;
384 /* 1 of 4 colors for each 2x1 or 1x2 block, need 8 more bytes */
385 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 8);
387 flags = bytestream_get_le64(&s->stream_ptr);
389 for (y = 0; y < 8; y++) {
390 for (x = 0; x < 8; x += 2, flags >>= 2) {
392 s->pixel_ptr[x + 1] = P[flags & 0x03];
394 s->pixel_ptr += s->stride;
397 for (y = 0; y < 8; y += 2) {
398 for (x = 0; x < 8; x++, flags >>= 2) {
400 s->pixel_ptr[x + s->stride] = P[flags & 0x03];
402 s->pixel_ptr += s->stride * 2;
411 static int ipvideo_decode_block_opcode_0xA(IpvideoContext *s)
417 /* 4-color encoding for each 4x4 quadrant, or 4-color encoding on
418 * either top and bottom or left and right halves */
419 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 24);
421 if (s->stream_ptr[0] <= s->stream_ptr[1]) {
423 /* 4-color encoding for each quadrant; need 32 bytes */
424 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 32);
426 for (y = 0; y < 16; y++) {
427 // new values for each 4x4 block
429 memcpy(P, s->stream_ptr, 4);
431 flags = bytestream_get_le32(&s->stream_ptr);
434 for (x = 0; x < 4; x++, flags >>= 2)
435 *s->pixel_ptr++ = P[flags & 0x03];
437 s->pixel_ptr += s->stride - 4;
438 // switch to right half
439 if (y == 7) s->pixel_ptr -= 8 * s->stride - 4;
444 int vert = s->stream_ptr[12] <= s->stream_ptr[13];
447 /* 4-color encoding for either left and right or top and bottom
450 for (y = 0; y < 16; y++) {
451 // load values for each half
453 memcpy(P, s->stream_ptr, 4);
455 flags = bytestream_get_le64(&s->stream_ptr);
458 for (x = 0; x < 4; x++, flags >>= 2)
459 *s->pixel_ptr++ = P[flags & 0x03];
462 s->pixel_ptr += s->stride - 4;
463 // switch to right half
464 if (y == 7) s->pixel_ptr -= 8 * s->stride - 4;
465 } else if (y & 1) s->pixel_ptr += s->line_inc;
473 static int ipvideo_decode_block_opcode_0xB(IpvideoContext *s)
477 /* 64-color encoding (each pixel in block is a different color) */
478 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 64);
480 for (y = 0; y < 8; y++) {
481 memcpy(s->pixel_ptr, s->stream_ptr, 8);
483 s->pixel_ptr += s->stride;
490 static int ipvideo_decode_block_opcode_0xC(IpvideoContext *s)
494 /* 16-color block encoding: each 2x2 block is a different color */
495 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 16);
497 for (y = 0; y < 8; y += 2) {
498 for (x = 0; x < 8; x += 2) {
500 s->pixel_ptr[x + 1 ] =
501 s->pixel_ptr[x + s->stride] =
502 s->pixel_ptr[x + 1 + s->stride] = *s->stream_ptr++;
504 s->pixel_ptr += s->stride * 2;
511 static int ipvideo_decode_block_opcode_0xD(IpvideoContext *s)
516 /* 4-color block encoding: each 4x4 block is a different color */
517 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 4);
519 for (y = 0; y < 8; y++) {
521 P[0] = *s->stream_ptr++;
522 P[1] = *s->stream_ptr++;
524 memset(s->pixel_ptr, P[0], 4);
525 memset(s->pixel_ptr + 4, P[1], 4);
526 s->pixel_ptr += s->stride;
533 static int ipvideo_decode_block_opcode_0xE(IpvideoContext *s)
538 /* 1-color encoding: the whole block is 1 solid color */
539 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 1);
540 pix = *s->stream_ptr++;
542 for (y = 0; y < 8; y++) {
543 memset(s->pixel_ptr, pix, 8);
544 s->pixel_ptr += s->stride;
551 static int ipvideo_decode_block_opcode_0xF(IpvideoContext *s)
554 unsigned char sample[2];
556 /* dithered encoding */
557 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2);
558 sample[0] = *s->stream_ptr++;
559 sample[1] = *s->stream_ptr++;
561 for (y = 0; y < 8; y++) {
562 for (x = 0; x < 8; x += 2) {
563 *s->pixel_ptr++ = sample[ y & 1 ];
564 *s->pixel_ptr++ = sample[!(y & 1)];
566 s->pixel_ptr += s->line_inc;
573 static int ipvideo_decode_block_opcode_0x6_16(IpvideoContext *s)
577 /* copy a block from the second last frame using an expanded range */
578 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2);
580 x = *s->stream_ptr++;
581 y = *s->stream_ptr++;
583 av_dlog(NULL, " motion bytes = %d, %d\n", x, y);
584 return copy_from(s, &s->second_last_frame, x, y);
587 static int ipvideo_decode_block_opcode_0x7_16(IpvideoContext *s)
592 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
594 /* 2-color encoding */
595 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 4);
597 P[0] = bytestream_get_le16(&s->stream_ptr);
598 P[1] = bytestream_get_le16(&s->stream_ptr);
600 if (!(P[0] & 0x8000)) {
602 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 8);
604 for (y = 0; y < 8; y++) {
605 flags = *s->stream_ptr++ | 0x100;
606 for (; flags != 1; flags >>= 1)
607 *pixel_ptr++ = P[flags & 1];
608 pixel_ptr += s->line_inc;
613 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2);
615 flags = bytestream_get_le16(&s->stream_ptr);
616 for (y = 0; y < 8; y += 2) {
617 for (x = 0; x < 8; x += 2, flags >>= 1) {
620 pixel_ptr[x + s->stride] =
621 pixel_ptr[x + 1 + s->stride] = P[flags & 1];
623 pixel_ptr += s->stride * 2;
630 static int ipvideo_decode_block_opcode_0x8_16(IpvideoContext *s)
634 unsigned int flags = 0;
635 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
637 /* 2-color encoding for each 4x4 quadrant, or 2-color encoding on
638 * either top and bottom or left and right halves */
639 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 4);
641 P[0] = bytestream_get_le16(&s->stream_ptr);
642 P[1] = bytestream_get_le16(&s->stream_ptr);
644 if (!(P[0] & 0x8000)) {
646 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 24);
649 for (y = 0; y < 16; y++) {
650 // new values for each 4x4 block
652 P[0] = bytestream_get_le16(&s->stream_ptr);
653 P[1] = bytestream_get_le16(&s->stream_ptr);
654 flags = bytestream_get_le16(&s->stream_ptr);
657 for (x = 0; x < 4; x++, flags >>= 1)
658 *pixel_ptr++ = P[flags & 1];
659 pixel_ptr += s->stride - 4;
660 // switch to right half
661 if (y == 7) pixel_ptr -= 8 * s->stride - 4;
666 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 12);
668 if (!(AV_RL16(s->stream_ptr + 4) & 0x8000)) {
670 flags = bytestream_get_le32(&s->stream_ptr);
672 /* vertical split; left & right halves are 2-color encoded */
674 for (y = 0; y < 16; y++) {
675 for (x = 0; x < 4; x++, flags >>= 1)
676 *pixel_ptr++ = P[flags & 1];
677 pixel_ptr += s->stride - 4;
678 // switch to right half
680 pixel_ptr -= 8 * s->stride - 4;
681 P[0] = bytestream_get_le16(&s->stream_ptr);
682 P[1] = bytestream_get_le16(&s->stream_ptr);
683 flags = bytestream_get_le32(&s->stream_ptr);
689 /* horizontal split; top & bottom halves are 2-color encoded */
691 for (y = 0; y < 8; y++) {
693 P[0] = bytestream_get_le16(&s->stream_ptr);
694 P[1] = bytestream_get_le16(&s->stream_ptr);
696 flags = *s->stream_ptr++ | 0x100;
698 for (; flags != 1; flags >>= 1)
699 *pixel_ptr++ = P[flags & 1];
700 pixel_ptr += s->line_inc;
709 static int ipvideo_decode_block_opcode_0x9_16(IpvideoContext *s)
713 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
715 /* 4-color encoding */
716 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 8);
718 for (x = 0; x < 4; x++)
719 P[x] = bytestream_get_le16(&s->stream_ptr);
721 if (!(P[0] & 0x8000)) {
722 if (!(P[2] & 0x8000)) {
724 /* 1 of 4 colors for each pixel */
725 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 16);
727 for (y = 0; y < 8; y++) {
728 /* get the next set of 8 2-bit flags */
729 int flags = bytestream_get_le16(&s->stream_ptr);
730 for (x = 0; x < 8; x++, flags >>= 2)
731 *pixel_ptr++ = P[flags & 0x03];
732 pixel_ptr += s->line_inc;
738 /* 1 of 4 colors for each 2x2 block */
739 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 4);
741 flags = bytestream_get_le32(&s->stream_ptr);
743 for (y = 0; y < 8; y += 2) {
744 for (x = 0; x < 8; x += 2, flags >>= 2) {
747 pixel_ptr[x + s->stride] =
748 pixel_ptr[x + 1 + s->stride] = P[flags & 0x03];
750 pixel_ptr += s->stride * 2;
757 /* 1 of 4 colors for each 2x1 or 1x2 block */
758 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 8);
760 flags = bytestream_get_le64(&s->stream_ptr);
761 if (!(P[2] & 0x8000)) {
762 for (y = 0; y < 8; y++) {
763 for (x = 0; x < 8; x += 2, flags >>= 2) {
765 pixel_ptr[x + 1] = P[flags & 0x03];
767 pixel_ptr += s->stride;
770 for (y = 0; y < 8; y += 2) {
771 for (x = 0; x < 8; x++, flags >>= 2) {
773 pixel_ptr[x + s->stride] = P[flags & 0x03];
775 pixel_ptr += s->stride * 2;
784 static int ipvideo_decode_block_opcode_0xA_16(IpvideoContext *s)
789 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
791 /* 4-color encoding for each 4x4 quadrant, or 4-color encoding on
792 * either top and bottom or left and right halves */
793 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 24);
795 if (!(AV_RL16(s->stream_ptr) & 0x8000)) {
797 /* 4-color encoding for each quadrant */
798 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 48);
800 for (y = 0; y < 16; y++) {
801 // new values for each 4x4 block
803 for (x = 0; x < 4; x++)
804 P[x] = bytestream_get_le16(&s->stream_ptr);
805 flags = bytestream_get_le32(&s->stream_ptr);
808 for (x = 0; x < 4; x++, flags >>= 2)
809 *pixel_ptr++ = P[flags & 0x03];
811 pixel_ptr += s->stride - 4;
812 // switch to right half
813 if (y == 7) pixel_ptr -= 8 * s->stride - 4;
818 int vert = !(AV_RL16(s->stream_ptr + 16) & 0x8000);
821 /* 4-color encoding for either left and right or top and bottom
824 for (y = 0; y < 16; y++) {
825 // load values for each half
827 for (x = 0; x < 4; x++)
828 P[x] = bytestream_get_le16(&s->stream_ptr);
829 flags = bytestream_get_le64(&s->stream_ptr);
832 for (x = 0; x < 4; x++, flags >>= 2)
833 *pixel_ptr++ = P[flags & 0x03];
836 pixel_ptr += s->stride - 4;
837 // switch to right half
838 if (y == 7) pixel_ptr -= 8 * s->stride - 4;
839 } else if (y & 1) pixel_ptr += s->line_inc;
847 static int ipvideo_decode_block_opcode_0xB_16(IpvideoContext *s)
850 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
852 /* 64-color encoding (each pixel in block is a different color) */
853 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 128);
855 for (y = 0; y < 8; y++) {
856 for (x = 0; x < 8; x++)
857 pixel_ptr[x] = bytestream_get_le16(&s->stream_ptr);
858 pixel_ptr += s->stride;
865 static int ipvideo_decode_block_opcode_0xC_16(IpvideoContext *s)
868 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
870 /* 16-color block encoding: each 2x2 block is a different color */
871 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 32);
873 for (y = 0; y < 8; y += 2) {
874 for (x = 0; x < 8; x += 2) {
877 pixel_ptr[x + s->stride] =
878 pixel_ptr[x + 1 + s->stride] = bytestream_get_le16(&s->stream_ptr);
880 pixel_ptr += s->stride * 2;
887 static int ipvideo_decode_block_opcode_0xD_16(IpvideoContext *s)
891 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
893 /* 4-color block encoding: each 4x4 block is a different color */
894 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 8);
896 for (y = 0; y < 8; y++) {
898 P[0] = bytestream_get_le16(&s->stream_ptr);
899 P[1] = bytestream_get_le16(&s->stream_ptr);
901 for (x = 0; x < 8; x++)
902 pixel_ptr[x] = P[x >> 2];
903 pixel_ptr += s->stride;
910 static int ipvideo_decode_block_opcode_0xE_16(IpvideoContext *s)
914 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
916 /* 1-color encoding: the whole block is 1 solid color */
917 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2);
918 pix = bytestream_get_le16(&s->stream_ptr);
920 for (y = 0; y < 8; y++) {
921 for (x = 0; x < 8; x++)
923 pixel_ptr += s->stride;
930 static int (* const ipvideo_decode_block[])(IpvideoContext *s) = {
931 ipvideo_decode_block_opcode_0x0, ipvideo_decode_block_opcode_0x1,
932 ipvideo_decode_block_opcode_0x2, ipvideo_decode_block_opcode_0x3,
933 ipvideo_decode_block_opcode_0x4, ipvideo_decode_block_opcode_0x5,
934 ipvideo_decode_block_opcode_0x6, ipvideo_decode_block_opcode_0x7,
935 ipvideo_decode_block_opcode_0x8, ipvideo_decode_block_opcode_0x9,
936 ipvideo_decode_block_opcode_0xA, ipvideo_decode_block_opcode_0xB,
937 ipvideo_decode_block_opcode_0xC, ipvideo_decode_block_opcode_0xD,
938 ipvideo_decode_block_opcode_0xE, ipvideo_decode_block_opcode_0xF,
941 static int (* const ipvideo_decode_block16[])(IpvideoContext *s) = {
942 ipvideo_decode_block_opcode_0x0, ipvideo_decode_block_opcode_0x1,
943 ipvideo_decode_block_opcode_0x2, ipvideo_decode_block_opcode_0x3,
944 ipvideo_decode_block_opcode_0x4, ipvideo_decode_block_opcode_0x5,
945 ipvideo_decode_block_opcode_0x6_16, ipvideo_decode_block_opcode_0x7_16,
946 ipvideo_decode_block_opcode_0x8_16, ipvideo_decode_block_opcode_0x9_16,
947 ipvideo_decode_block_opcode_0xA_16, ipvideo_decode_block_opcode_0xB_16,
948 ipvideo_decode_block_opcode_0xC_16, ipvideo_decode_block_opcode_0xD_16,
949 ipvideo_decode_block_opcode_0xE_16, ipvideo_decode_block_opcode_0x1,
952 static void ipvideo_decode_opcodes(IpvideoContext *s)
955 unsigned char opcode;
957 static int frame = 0;
960 av_dlog(NULL, "------------------ frame %d\n", frame);
964 /* this is PAL8, so make the palette available */
965 memcpy(s->current_frame.data[1], s->pal, AVPALETTE_SIZE);
967 s->stride = s->current_frame.linesize[0];
968 s->stream_ptr = s->buf + 14; /* data starts 14 bytes in */
969 s->stream_end = s->buf + s->size;
971 s->stride = s->current_frame.linesize[0] >> 1;
972 s->stream_ptr = s->buf + 16;
974 s->mv_ptr = s->buf + 14 + AV_RL16(s->buf+14);
975 s->mv_end = s->buf + s->size;
977 s->line_inc = s->stride - 8;
978 s->upper_motion_limit_offset = (s->avctx->height - 8) * s->current_frame.linesize[0]
979 + (s->avctx->width - 8) * (1 + s->is_16bpp);
981 init_get_bits(&gb, s->decoding_map, s->decoding_map_size * 8);
982 for (y = 0; y < s->avctx->height; y += 8) {
983 for (x = 0; x < s->avctx->width; x += 8) {
984 opcode = get_bits(&gb, 4);
986 av_dlog(NULL, " block @ (%3d, %3d): encoding 0x%X, data ptr @ %p\n",
987 x, y, opcode, s->stream_ptr);
990 s->pixel_ptr = s->current_frame.data[0] + x
991 + y*s->current_frame.linesize[0];
992 ret = ipvideo_decode_block[opcode](s);
994 s->pixel_ptr = s->current_frame.data[0] + x*2
995 + y*s->current_frame.linesize[0];
996 ret = ipvideo_decode_block16[opcode](s);
999 av_log(s->avctx, AV_LOG_ERROR, " Interplay video: decode problem on frame %d, @ block (%d, %d)\n",
1005 if (s->stream_end - s->stream_ptr > 1) {
1006 av_log(s->avctx, AV_LOG_ERROR, " Interplay video: decode finished with %td bytes left over\n",
1007 s->stream_end - s->stream_ptr);
1011 static av_cold int ipvideo_decode_init(AVCodecContext *avctx)
1013 IpvideoContext *s = avctx->priv_data;
1017 s->is_16bpp = avctx->bits_per_coded_sample == 16;
1018 avctx->pix_fmt = s->is_16bpp ? PIX_FMT_RGB555 : PIX_FMT_PAL8;
1020 dsputil_init(&s->dsp, avctx);
1022 avcodec_get_frame_defaults(&s->second_last_frame);
1023 avcodec_get_frame_defaults(&s->last_frame);
1024 avcodec_get_frame_defaults(&s->current_frame);
1026 s->current_frame.data[0] = s->last_frame.data[0] =
1027 s->second_last_frame.data[0] = NULL;
1032 static int ipvideo_decode_frame(AVCodecContext *avctx,
1033 void *data, int *data_size,
1036 const uint8_t *buf = avpkt->data;
1037 int buf_size = avpkt->size;
1038 IpvideoContext *s = avctx->priv_data;
1040 /* decoding map contains 4 bits of information per 8x8 block */
1041 s->decoding_map_size = avctx->width * avctx->height / (8 * 8 * 2);
1043 /* compressed buffer needs to be large enough to at least hold an entire
1045 if (buf_size < s->decoding_map_size)
1048 s->decoding_map = buf;
1049 s->buf = buf + s->decoding_map_size;
1050 s->size = buf_size - s->decoding_map_size;
1052 s->current_frame.reference = 3;
1053 if (avctx->get_buffer(avctx, &s->current_frame)) {
1054 av_log(avctx, AV_LOG_ERROR, " Interplay Video: get_buffer() failed\n");
1059 const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, NULL);
1061 s->current_frame.palette_has_changed = 1;
1062 memcpy(s->pal, pal, AVPALETTE_SIZE);
1066 ipvideo_decode_opcodes(s);
1068 *data_size = sizeof(AVFrame);
1069 *(AVFrame*)data = s->current_frame;
1071 /* shuffle frames */
1072 if (s->second_last_frame.data[0])
1073 avctx->release_buffer(avctx, &s->second_last_frame);
1074 s->second_last_frame = s->last_frame;
1075 s->last_frame = s->current_frame;
1076 s->current_frame.data[0] = NULL; /* catch any access attempts */
1078 /* report that the buffer was completely consumed */
1082 static av_cold int ipvideo_decode_end(AVCodecContext *avctx)
1084 IpvideoContext *s = avctx->priv_data;
1086 /* release the last frame */
1087 if (s->last_frame.data[0])
1088 avctx->release_buffer(avctx, &s->last_frame);
1089 if (s->second_last_frame.data[0])
1090 avctx->release_buffer(avctx, &s->second_last_frame);
1095 AVCodec ff_interplay_video_decoder = {
1096 .name = "interplayvideo",
1097 .type = AVMEDIA_TYPE_VIDEO,
1098 .id = CODEC_ID_INTERPLAY_VIDEO,
1099 .priv_data_size = sizeof(IpvideoContext),
1100 .init = ipvideo_decode_init,
1101 .close = ipvideo_decode_end,
1102 .decode = ipvideo_decode_frame,
1103 .capabilities = CODEC_CAP_DR1 | CODEC_CAP_PARAM_CHANGE,
1104 .long_name = NULL_IF_CONFIG_SMALL("Interplay MVE video"),