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
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.
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.
43 #include "bytestream.h"
46 #define PALETTE_COUNT 256
48 /* debugging support */
49 #define DEBUG_INTERPLAY 0
51 #define debug_interplay(x,...) av_log(NULL, AV_LOG_DEBUG, x, __VA_ARGS__)
53 static inline void debug_interplay(const char *format
, ...) { }
56 typedef struct IpvideoContext
{
58 AVCodecContext
*avctx
;
60 AVFrame second_last_frame
;
62 AVFrame current_frame
;
63 const unsigned char *decoding_map
;
64 int decoding_map_size
;
66 const unsigned char *buf
;
69 const unsigned char *stream_ptr
;
70 const unsigned char *stream_end
;
71 unsigned char *pixel_ptr
;
74 int upper_motion_limit_offset
;
78 #define CHECK_STREAM_PTR(n) \
79 if (s->stream_end - s->stream_ptr < n) { \
80 av_log(s->avctx, AV_LOG_ERROR, "Interplay video warning: stream_ptr out of bounds (%p >= %p)\n", \
81 s->stream_ptr + n, s->stream_end); \
85 static int copy_from(IpvideoContext
*s
, AVFrame
*src
, int delta_x
, int delta_y
)
87 int current_offset
= s
->pixel_ptr
- s
->current_frame
.data
[0];
88 int motion_offset
= current_offset
+ delta_y
* s
->stride
+ delta_x
;
89 if (motion_offset
< 0) {
90 av_log(s
->avctx
, AV_LOG_ERROR
, " Interplay video: motion offset < 0 (%d)\n", motion_offset
);
92 } else if (motion_offset
> s
->upper_motion_limit_offset
) {
93 av_log(s
->avctx
, AV_LOG_ERROR
, " Interplay video: motion offset above limit (%d >= %d)\n",
94 motion_offset
, s
->upper_motion_limit_offset
);
97 s
->dsp
.put_pixels_tab
[1][0](s
->pixel_ptr
, src
->data
[0] + motion_offset
, s
->stride
, 8);
101 static int ipvideo_decode_block_opcode_0x0(IpvideoContext
*s
)
103 return copy_from(s
, &s
->last_frame
, 0, 0);
106 static int ipvideo_decode_block_opcode_0x1(IpvideoContext
*s
)
108 return copy_from(s
, &s
->second_last_frame
, 0, 0);
111 static int ipvideo_decode_block_opcode_0x2(IpvideoContext
*s
)
116 /* copy block from 2 frames ago using a motion vector; need 1 more byte */
118 B
= *s
->stream_ptr
++;
124 x
= -14 + ((B
- 56) % 29);
125 y
= 8 + ((B
- 56) / 29);
128 debug_interplay (" motion byte = %d, (x, y) = (%d, %d)\n", B
, x
, y
);
129 return copy_from(s
, &s
->second_last_frame
, x
, y
);
132 static int ipvideo_decode_block_opcode_0x3(IpvideoContext
*s
)
137 /* copy 8x8 block from current frame from an up/left block */
139 /* need 1 more byte for motion */
141 B
= *s
->stream_ptr
++;
147 x
= -(-14 + ((B
- 56) % 29));
148 y
= -( 8 + ((B
- 56) / 29));
151 debug_interplay (" motion byte = %d, (x, y) = (%d, %d)\n", B
, x
, y
);
152 return copy_from(s
, &s
->current_frame
, x
, y
);
155 static int ipvideo_decode_block_opcode_0x4(IpvideoContext
*s
)
158 unsigned char B
, BL
, BH
;
160 /* copy a block from the previous frame; need 1 more byte */
163 B
= *s
->stream_ptr
++;
165 BH
= (B
>> 4) & 0x0F;
169 debug_interplay (" motion byte = %d, (x, y) = (%d, %d)\n", B
, x
, y
);
170 return copy_from(s
, &s
->last_frame
, x
, y
);
173 static int ipvideo_decode_block_opcode_0x5(IpvideoContext
*s
)
177 /* copy a block from the previous frame using an expanded range;
178 * need 2 more bytes */
181 x
= *s
->stream_ptr
++;
182 y
= *s
->stream_ptr
++;
184 debug_interplay (" motion bytes = %d, %d\n", x
, y
);
185 return copy_from(s
, &s
->last_frame
, x
, y
);
188 static int ipvideo_decode_block_opcode_0x6(IpvideoContext
*s
)
190 /* mystery opcode? skip multiple blocks? */
191 av_log(s
->avctx
, AV_LOG_ERROR
, " Interplay video: Help! Mystery opcode 0x6 seen\n");
197 static int ipvideo_decode_block_opcode_0x7(IpvideoContext
*s
)
203 /* 2-color encoding */
206 P
[0] = *s
->stream_ptr
++;
207 P
[1] = *s
->stream_ptr
++;
211 /* need 8 more bytes from the stream */
214 for (y
= 0; y
< 8; y
++) {
215 flags
= *s
->stream_ptr
++ | 0x100;
216 for (; flags
!= 1; flags
>>= 1)
217 *s
->pixel_ptr
++ = P
[flags
& 1];
218 s
->pixel_ptr
+= s
->line_inc
;
223 /* need 2 more bytes from the stream */
226 flags
= bytestream_get_le16(&s
->stream_ptr
);
227 for (y
= 0; y
< 8; y
+= 2) {
228 for (x
= 0; x
< 8; x
+= 2, flags
>>= 1) {
230 s
->pixel_ptr
[x
+ 1 ] =
231 s
->pixel_ptr
[x
+ s
->stride
] =
232 s
->pixel_ptr
[x
+ 1 + s
->stride
] = P
[flags
& 1];
234 s
->pixel_ptr
+= s
->stride
* 2;
242 static int ipvideo_decode_block_opcode_0x8(IpvideoContext
*s
)
246 unsigned int flags
= 0;
248 /* 2-color encoding for each 4x4 quadrant, or 2-color encoding on
249 * either top and bottom or left and right halves */
252 P
[0] = *s
->stream_ptr
++;
253 P
[1] = *s
->stream_ptr
++;
257 CHECK_STREAM_PTR(14);
260 for (y
= 0; y
< 16; y
++) {
261 // new values for each 4x4 block
263 P
[0] = *s
->stream_ptr
++; P
[1] = *s
->stream_ptr
++;
264 flags
= bytestream_get_le16(&s
->stream_ptr
);
267 for (x
= 0; x
< 4; x
++, flags
>>= 1)
268 *s
->pixel_ptr
++ = P
[flags
& 1];
269 s
->pixel_ptr
+= s
->stride
- 4;
270 // switch to right half
271 if (y
== 7) s
->pixel_ptr
-= 8 * s
->stride
- 4;
276 /* need 10 more bytes */
277 CHECK_STREAM_PTR(10);
279 if (s
->stream_ptr
[4] <= s
->stream_ptr
[5]) {
281 flags
= bytestream_get_le32(&s
->stream_ptr
);
283 /* vertical split; left & right halves are 2-color encoded */
285 for (y
= 0; y
< 16; y
++) {
286 for (x
= 0; x
< 4; x
++, flags
>>= 1)
287 *s
->pixel_ptr
++ = P
[flags
& 1];
288 s
->pixel_ptr
+= s
->stride
- 4;
289 // switch to right half
291 s
->pixel_ptr
-= 8 * s
->stride
- 4;
292 P
[0] = *s
->stream_ptr
++; P
[1] = *s
->stream_ptr
++;
293 flags
= bytestream_get_le32(&s
->stream_ptr
);
299 /* horizontal split; top & bottom halves are 2-color encoded */
301 for (y
= 0; y
< 8; y
++) {
303 P
[0] = *s
->stream_ptr
++;
304 P
[1] = *s
->stream_ptr
++;
306 flags
= *s
->stream_ptr
++ | 0x100;
308 for (; flags
!= 1; flags
>>= 1)
309 *s
->pixel_ptr
++ = P
[flags
& 1];
310 s
->pixel_ptr
+= s
->line_inc
;
319 static int ipvideo_decode_block_opcode_0x9(IpvideoContext
*s
)
324 /* 4-color encoding */
327 memcpy(P
, s
->stream_ptr
, 4);
333 /* 1 of 4 colors for each pixel, need 16 more bytes */
334 CHECK_STREAM_PTR(16);
336 for (y
= 0; y
< 8; y
++) {
337 /* get the next set of 8 2-bit flags */
338 int flags
= bytestream_get_le16(&s
->stream_ptr
);
339 for (x
= 0; x
< 8; x
++, flags
>>= 2)
340 *s
->pixel_ptr
++ = P
[flags
& 0x03];
341 s
->pixel_ptr
+= s
->line_inc
;
347 /* 1 of 4 colors for each 2x2 block, need 4 more bytes */
350 flags
= bytestream_get_le32(&s
->stream_ptr
);
352 for (y
= 0; y
< 8; y
+= 2) {
353 for (x
= 0; x
< 8; x
+= 2, flags
>>= 2) {
355 s
->pixel_ptr
[x
+ 1 ] =
356 s
->pixel_ptr
[x
+ s
->stride
] =
357 s
->pixel_ptr
[x
+ 1 + s
->stride
] = P
[flags
& 0x03];
359 s
->pixel_ptr
+= s
->stride
* 2;
366 /* 1 of 4 colors for each 2x1 or 1x2 block, need 8 more bytes */
369 flags
= bytestream_get_le64(&s
->stream_ptr
);
371 for (y
= 0; y
< 8; y
++) {
372 for (x
= 0; x
< 8; x
+= 2, flags
>>= 2) {
374 s
->pixel_ptr
[x
+ 1] = P
[flags
& 0x03];
376 s
->pixel_ptr
+= s
->stride
;
379 for (y
= 0; y
< 8; y
+= 2) {
380 for (x
= 0; x
< 8; x
++, flags
>>= 2) {
382 s
->pixel_ptr
[x
+ s
->stride
] = P
[flags
& 0x03];
384 s
->pixel_ptr
+= s
->stride
* 2;
393 static int ipvideo_decode_block_opcode_0xA(IpvideoContext
*s
)
399 /* 4-color encoding for each 4x4 quadrant, or 4-color encoding on
400 * either top and bottom or left and right halves */
401 CHECK_STREAM_PTR(24);
403 if (s
->stream_ptr
[0] <= s
->stream_ptr
[1]) {
405 /* 4-color encoding for each quadrant; need 32 bytes */
406 CHECK_STREAM_PTR(32);
408 for (y
= 0; y
< 16; y
++) {
409 // new values for each 4x4 block
411 memcpy(P
, s
->stream_ptr
, 4);
413 flags
= bytestream_get_le32(&s
->stream_ptr
);
416 for (x
= 0; x
< 4; x
++, flags
>>= 2)
417 *s
->pixel_ptr
++ = P
[flags
& 0x03];
419 s
->pixel_ptr
+= s
->stride
- 4;
420 // switch to right half
421 if (y
== 7) s
->pixel_ptr
-= 8 * s
->stride
- 4;
426 int vert
= s
->stream_ptr
[12] <= s
->stream_ptr
[13];
429 /* 4-color encoding for either left and right or top and bottom
432 for (y
= 0; y
< 16; y
++) {
433 // load values for each half
435 memcpy(P
, s
->stream_ptr
, 4);
437 flags
= bytestream_get_le64(&s
->stream_ptr
);
440 for (x
= 0; x
< 4; x
++, flags
>>= 2)
441 *s
->pixel_ptr
++ = P
[flags
& 0x03];
444 s
->pixel_ptr
+= s
->stride
- 4;
445 // switch to right half
446 if (y
== 7) s
->pixel_ptr
-= 8 * s
->stride
- 4;
447 } else if (y
& 1) s
->pixel_ptr
+= s
->line_inc
;
455 static int ipvideo_decode_block_opcode_0xB(IpvideoContext
*s
)
459 /* 64-color encoding (each pixel in block is a different color) */
460 CHECK_STREAM_PTR(64);
462 for (y
= 0; y
< 8; y
++) {
463 memcpy(s
->pixel_ptr
, s
->stream_ptr
, 8);
465 s
->pixel_ptr
+= s
->stride
;
472 static int ipvideo_decode_block_opcode_0xC(IpvideoContext
*s
)
476 /* 16-color block encoding: each 2x2 block is a different color */
477 CHECK_STREAM_PTR(16);
479 for (y
= 0; y
< 8; y
+= 2) {
480 for (x
= 0; x
< 8; x
+= 2) {
482 s
->pixel_ptr
[x
+ 1 ] =
483 s
->pixel_ptr
[x
+ s
->stride
] =
484 s
->pixel_ptr
[x
+ 1 + s
->stride
] = *s
->stream_ptr
++;
486 s
->pixel_ptr
+= s
->stride
* 2;
493 static int ipvideo_decode_block_opcode_0xD(IpvideoContext
*s
)
498 /* 4-color block encoding: each 4x4 block is a different color */
501 for (y
= 0; y
< 8; y
++) {
503 P
[0] = *s
->stream_ptr
++;
504 P
[1] = *s
->stream_ptr
++;
506 memset(s
->pixel_ptr
, P
[0], 4);
507 memset(s
->pixel_ptr
+ 4, P
[1], 4);
508 s
->pixel_ptr
+= s
->stride
;
515 static int ipvideo_decode_block_opcode_0xE(IpvideoContext
*s
)
520 /* 1-color encoding: the whole block is 1 solid color */
522 pix
= *s
->stream_ptr
++;
524 for (y
= 0; y
< 8; y
++) {
525 memset(s
->pixel_ptr
, pix
, 8);
526 s
->pixel_ptr
+= s
->stride
;
533 static int ipvideo_decode_block_opcode_0xF(IpvideoContext
*s
)
536 unsigned char sample
[2];
538 /* dithered encoding */
540 sample
[0] = *s
->stream_ptr
++;
541 sample
[1] = *s
->stream_ptr
++;
543 for (y
= 0; y
< 8; y
++) {
544 for (x
= 0; x
< 8; x
+= 2) {
545 *s
->pixel_ptr
++ = sample
[ y
& 1 ];
546 *s
->pixel_ptr
++ = sample
[!(y
& 1)];
548 s
->pixel_ptr
+= s
->line_inc
;
555 static int (* const ipvideo_decode_block
[])(IpvideoContext
*s
) = {
556 ipvideo_decode_block_opcode_0x0
, ipvideo_decode_block_opcode_0x1
,
557 ipvideo_decode_block_opcode_0x2
, ipvideo_decode_block_opcode_0x3
,
558 ipvideo_decode_block_opcode_0x4
, ipvideo_decode_block_opcode_0x5
,
559 ipvideo_decode_block_opcode_0x6
, ipvideo_decode_block_opcode_0x7
,
560 ipvideo_decode_block_opcode_0x8
, ipvideo_decode_block_opcode_0x9
,
561 ipvideo_decode_block_opcode_0xA
, ipvideo_decode_block_opcode_0xB
,
562 ipvideo_decode_block_opcode_0xC
, ipvideo_decode_block_opcode_0xD
,
563 ipvideo_decode_block_opcode_0xE
, ipvideo_decode_block_opcode_0xF
,
566 static void ipvideo_decode_opcodes(IpvideoContext
*s
)
570 unsigned char opcode
;
572 int code_counts
[16] = {0};
573 static int frame
= 0;
575 debug_interplay("------------------ frame %d\n", frame
);
578 /* this is PAL8, so make the palette available */
579 memcpy(s
->current_frame
.data
[1], s
->avctx
->palctrl
->palette
, PALETTE_COUNT
* 4);
581 s
->stride
= s
->current_frame
.linesize
[0];
582 s
->stream_ptr
= s
->buf
+ 14; /* data starts 14 bytes in */
583 s
->stream_end
= s
->buf
+ s
->size
;
584 s
->line_inc
= s
->stride
- 8;
585 s
->upper_motion_limit_offset
= (s
->avctx
->height
- 8) * s
->stride
586 + s
->avctx
->width
- 8;
588 for (y
= 0; y
< (s
->stride
* s
->avctx
->height
); y
+= s
->stride
* 8) {
589 for (x
= y
; x
< y
+ s
->avctx
->width
; x
+= 8) {
590 /* bottom nibble first, then top nibble (which makes it
591 * hard to use a GetBitcontext) */
593 opcode
= s
->decoding_map
[index
>> 1] >> 4;
595 opcode
= s
->decoding_map
[index
>> 1] & 0xF;
598 debug_interplay(" block @ (%3d, %3d): encoding 0x%X, data ptr @ %p\n",
599 x
- y
, y
/ s
->stride
, opcode
, s
->stream_ptr
);
600 code_counts
[opcode
]++;
602 s
->pixel_ptr
= s
->current_frame
.data
[0] + x
;
603 ret
= ipvideo_decode_block
[opcode
](s
);
605 av_log(s
->avctx
, AV_LOG_ERROR
, " Interplay video: decode problem on frame %d, @ block (%d, %d)\n",
606 frame
, x
- y
, y
/ s
->stride
);
611 if (s
->stream_end
- s
->stream_ptr
> 1) {
612 av_log(s
->avctx
, AV_LOG_ERROR
, " Interplay video: decode finished with %td bytes left over\n",
613 s
->stream_end
- s
->stream_ptr
);
617 static av_cold
int ipvideo_decode_init(AVCodecContext
*avctx
)
619 IpvideoContext
*s
= avctx
->priv_data
;
623 if (s
->avctx
->palctrl
== NULL
) {
624 av_log(avctx
, AV_LOG_ERROR
, " Interplay video: palette expected.\n");
628 avctx
->pix_fmt
= PIX_FMT_PAL8
;
629 dsputil_init(&s
->dsp
, avctx
);
631 /* decoding map contains 4 bits of information per 8x8 block */
632 s
->decoding_map_size
= avctx
->width
* avctx
->height
/ (8 * 8 * 2);
634 s
->current_frame
.data
[0] = s
->last_frame
.data
[0] =
635 s
->second_last_frame
.data
[0] = NULL
;
640 static int ipvideo_decode_frame(AVCodecContext
*avctx
,
641 void *data
, int *data_size
,
644 const uint8_t *buf
= avpkt
->data
;
645 int buf_size
= avpkt
->size
;
646 IpvideoContext
*s
= avctx
->priv_data
;
647 AVPaletteControl
*palette_control
= avctx
->palctrl
;
649 /* compressed buffer needs to be large enough to at least hold an entire
651 if (buf_size
< s
->decoding_map_size
)
654 s
->decoding_map
= buf
;
655 s
->buf
= buf
+ s
->decoding_map_size
;
656 s
->size
= buf_size
- s
->decoding_map_size
;
658 s
->current_frame
.reference
= 3;
659 if (avctx
->get_buffer(avctx
, &s
->current_frame
)) {
660 av_log(avctx
, AV_LOG_ERROR
, " Interplay Video: get_buffer() failed\n");
664 ipvideo_decode_opcodes(s
);
666 if (palette_control
->palette_changed
) {
667 palette_control
->palette_changed
= 0;
668 s
->current_frame
.palette_has_changed
= 1;
671 *data_size
= sizeof(AVFrame
);
672 *(AVFrame
*)data
= s
->current_frame
;
675 if (s
->second_last_frame
.data
[0])
676 avctx
->release_buffer(avctx
, &s
->second_last_frame
);
677 s
->second_last_frame
= s
->last_frame
;
678 s
->last_frame
= s
->current_frame
;
679 s
->current_frame
.data
[0] = NULL
; /* catch any access attempts */
681 /* report that the buffer was completely consumed */
685 static av_cold
int ipvideo_decode_end(AVCodecContext
*avctx
)
687 IpvideoContext
*s
= avctx
->priv_data
;
689 /* release the last frame */
690 if (s
->last_frame
.data
[0])
691 avctx
->release_buffer(avctx
, &s
->last_frame
);
692 if (s
->second_last_frame
.data
[0])
693 avctx
->release_buffer(avctx
, &s
->second_last_frame
);
698 AVCodec interplay_video_decoder
= {
701 CODEC_ID_INTERPLAY_VIDEO
,
702 sizeof(IpvideoContext
),
706 ipvideo_decode_frame
,
708 .long_name
= NULL_IF_CONFIG_SMALL("Interplay MVE video"),