2 * Interplay MVE Video Decoder
3 * Copyright (C) 2003 the ffmpeg project
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * @file interplayvideo.c
23 * Interplay MVE Video Decoder by Mike Melanson (melanson@pcisys.net)
24 * For more information about the Interplay MVE format, visit:
25 * http://www.pcisys.net/~melanson/codecs/interplay-mve.txt
26 * This code is written in such a way that the identifiers match up
27 * with the encoding descriptions in the document.
29 * This decoder presently only supports a PAL8 output colorspace.
31 * An Interplay video frame consists of 2 parts: The decoding map and
32 * the video data. A demuxer must load these 2 parts together in a single
33 * buffer before sending it through the stream to this decoder.
45 #define PALETTE_COUNT 256
47 /* debugging support */
48 #define DEBUG_INTERPLAY 0
50 #define debug_interplay printf
52 static inline void debug_interplay(const char *format
, ...) { }
55 typedef struct IpvideoContext
{
57 AVCodecContext
*avctx
;
60 AVFrame current_frame
;
62 unsigned char *decoding_map
;
63 int decoding_map_size
;
68 unsigned char palette
[PALETTE_COUNT
* 4];
72 #define CHECK_STREAM_PTR(n) \
73 if ((sg_stream_ptr + n) > sg_stream_end) { \
74 printf ("Interplay video warning: stream_ptr out of bounds (%p >= %p)\n", \
75 sg_stream_ptr + n, sg_stream_end); \
79 static void ipvideo_new_palette(IpvideoContext
*s
, unsigned char *palette
) {
82 unsigned char r
, g
, b
;
83 unsigned int *palette32
;
85 switch (s
->avctx
->pix_fmt
) {
88 palette32
= (unsigned int *)s
->palette
;
89 for (i
= 0; i
< PALETTE_COUNT
; i
++) {
93 palette32
[i
] = (r
<< 16) | (g
<< 8) | (b
);
98 printf ("Interplay video: Unhandled video format\n");
103 static unsigned char *sg_stream_ptr
;
104 static unsigned char *sg_stream_end
;
105 static unsigned char *sg_current_plane
;
106 static unsigned char *sg_output_plane
;
107 static unsigned char *sg_last_plane
;
108 static int sg_line_inc
;
109 static int sg_stride
;
110 static int sg_upper_motion_limit_offset
;
111 static DSPContext sg_dsp
;
113 static int ipvideo_decode_block_opcode_0x0_0x1(void)
116 unsigned char *src_block
;
118 /* skip block, which actually means to copy from previous frame */
119 src_block
= sg_last_plane
+ (sg_output_plane
- sg_current_plane
);
120 for (y
= 0; y
< 8; y
++) {
121 for (x
= 0; x
< 8; x
++) {
122 *sg_output_plane
++ = *src_block
++;
124 sg_output_plane
+= sg_line_inc
;
125 src_block
+= sg_line_inc
;
132 #define COPY_FROM_CURRENT() \
133 motion_offset = current_offset; \
134 motion_offset += y * sg_stride; \
135 motion_offset += x; \
136 if (motion_offset < 0) { \
137 printf (" Interplay video: motion offset < 0 (%d)\n", motion_offset); \
139 } else if (motion_offset > sg_upper_motion_limit_offset) { \
140 printf (" Interplay video: motion offset above limit (%d >= %d)\n", \
141 motion_offset, sg_upper_motion_limit_offset); \
144 sg_dsp.put_pixels_tab[0][0](sg_output_plane, \
145 sg_current_plane + motion_offset, sg_stride, 8);
147 #define COPY_FROM_PREVIOUS() \
148 motion_offset = current_offset; \
149 motion_offset += y * sg_stride; \
150 motion_offset += x; \
151 if (motion_offset < 0) { \
152 printf (" Interplay video: motion offset < 0 (%d)\n", motion_offset); \
154 } else if (motion_offset > sg_upper_motion_limit_offset) { \
155 printf (" Interplay video: motion offset above limit (%d >= %d)\n", \
156 motion_offset, sg_upper_motion_limit_offset); \
159 sg_dsp.put_pixels_tab[0][0](sg_output_plane, \
160 sg_last_plane + motion_offset, sg_stride, 8);
162 static int ipvideo_decode_block_opcode_0x2(void)
167 int current_offset
= sg_output_plane
- sg_current_plane
;
169 /* This is the opcode which claims to copy data from within the same
170 * frame at a coordinate which has not been rendered yet. Assume that
171 * it is supposed to be copied from the previous frame. */
173 /* need 1 more byte for motion */
175 B
= *sg_stream_ptr
++;
181 x
= -14 + ((B
- 56) % 29);
182 y
= 8 + ((B
- 56) / 29);
185 debug_interplay (" motion byte = %d, (x, y) = (%d, %d)\n", B
, x
, y
);
186 COPY_FROM_PREVIOUS();
192 static int ipvideo_decode_block_opcode_0x3(void)
197 int current_offset
= sg_output_plane
- sg_current_plane
;
199 /* copy 8x8 block from current frame from an up/left block */
201 /* need 1 more byte for motion */
203 B
= *sg_stream_ptr
++;
209 x
= -(-14 + ((B
- 56) % 29));
210 y
= -( 8 + ((B
- 56) / 29));
213 debug_interplay (" motion byte = %d, (x, y) = (%d, %d)\n", B
, x
, y
);
220 static int ipvideo_decode_block_opcode_0x4(void)
223 unsigned char B
, BL
, BH
;
225 int current_offset
= sg_output_plane
- sg_current_plane
;
227 /* copy a block from the previous frame; need 1 more byte */
230 B
= *sg_stream_ptr
++;
232 BH
= (B
>> 4) & 0x0F;
236 debug_interplay (" motion byte = %d, (x, y) = (%d, %d)\n", B
, x
, y
);
237 COPY_FROM_PREVIOUS();
243 static int ipvideo_decode_block_opcode_0x5(void)
247 int current_offset
= sg_output_plane
- sg_current_plane
;
249 /* copy a block from the previous frame using an expanded range;
250 * need 2 more bytes */
253 x
= *sg_stream_ptr
++;
254 y
= *sg_stream_ptr
++;
256 debug_interplay (" motion bytes = %d, %d\n", x
, y
);
257 COPY_FROM_PREVIOUS();
263 static int ipvideo_decode_block_opcode_0x6(void)
265 /* mystery opcode? skip multiple blocks? */
266 printf (" Interplay video: Help! Mystery opcode 0x6 seen\n");
272 static int ipvideo_decode_block_opcode_0x7(void)
275 unsigned char P0
, P1
;
280 /* 2-color encoding */
283 P0
= *sg_stream_ptr
++;
284 P1
= *sg_stream_ptr
++;
288 /* need 8 more bytes from the stream */
290 for (y
= 0; y
< 8; y
++)
291 B
[y
] = *sg_stream_ptr
++;
293 for (y
= 0; y
< 8; y
++) {
295 for (x
= 0x80; x
!= 0; x
>>= 1) {
297 *sg_output_plane
++ = P1
;
299 *sg_output_plane
++ = P0
;
301 sg_output_plane
+= sg_line_inc
;
306 /* need 2 more bytes from the stream */
308 B
[0] = *sg_stream_ptr
++;
309 B
[1] = *sg_stream_ptr
++;
311 flags
= (B
[0] << 8) | B
[1];
313 for (y
= 0; y
< 8; y
+= 2) {
314 for (x
= 0; x
< 8; x
+= 2, bitmask
>>= 1) {
315 if (flags
& bitmask
) {
316 *(sg_output_plane
+ x
) = P0
;
317 *(sg_output_plane
+ x
+ 1) = P0
;
318 *(sg_output_plane
+ sg_stride
+ x
) = P0
;
319 *(sg_output_plane
+ sg_stride
+ x
+ 1) = P0
;
321 *(sg_output_plane
+ x
) = P1
;
322 *(sg_output_plane
+ x
+ 1) = P1
;
323 *(sg_output_plane
+ sg_stride
+ x
) = P1
;
324 *(sg_output_plane
+ sg_stride
+ x
+ 1) = P1
;
327 sg_output_plane
+= sg_stride
* 2;
335 static int ipvideo_decode_block_opcode_0x8(void)
340 unsigned int flags
= 0;
341 unsigned int bitmask
= 0;
342 unsigned char P0
= 0, P1
= 0;
345 /* 2-color encoding for each 4x4 quadrant, or 2-color encoding on
346 * either top and bottom or left and right halves */
349 P
[0] = *sg_stream_ptr
++;
350 P
[1] = *sg_stream_ptr
++;
354 /* need 12 more bytes */
355 CHECK_STREAM_PTR(12);
356 B
[0] = *sg_stream_ptr
++; B
[1] = *sg_stream_ptr
++;
357 P
[2] = *sg_stream_ptr
++; P
[3] = *sg_stream_ptr
++;
358 B
[2] = *sg_stream_ptr
++; B
[3] = *sg_stream_ptr
++;
359 P
[4] = *sg_stream_ptr
++; P
[5] = *sg_stream_ptr
++;
360 B
[4] = *sg_stream_ptr
++; B
[5] = *sg_stream_ptr
++;
361 P
[6] = *sg_stream_ptr
++; P
[7] = *sg_stream_ptr
++;
362 B
[6] = *sg_stream_ptr
++; B
[7] = *sg_stream_ptr
++;
364 for (y
= 0; y
< 8; y
++) {
366 /* time to reload flags? */
369 ((B
[0] & 0xF0) << 24) | ((B
[4] & 0xF0) << 20) |
370 ((B
[0] & 0x0F) << 20) | ((B
[4] & 0x0F) << 16) |
371 ((B
[1] & 0xF0) << 8) | ((B
[5] & 0xF0) << 4) |
372 ((B
[1] & 0x0F) << 4) | ((B
[5] & 0x0F) << 0);
373 bitmask
= 0x80000000;
374 lower_half
= 0; /* still on top half */
377 ((B
[2] & 0xF0) << 24) | ((B
[6] & 0xF0) << 20) |
378 ((B
[2] & 0x0F) << 20) | ((B
[6] & 0x0F) << 16) |
379 ((B
[3] & 0xF0) << 8) | ((B
[7] & 0xF0) << 4) |
380 ((B
[3] & 0x0F) << 4) | ((B
[7] & 0x0F) << 0);
381 bitmask
= 0x80000000;
385 for (x
= 0; x
< 8; x
++, bitmask
>>= 1) {
386 /* get the pixel values ready for this quadrant */
388 P0
= P
[lower_half
+ 0];
389 P1
= P
[lower_half
+ 1];
391 P0
= P
[lower_half
+ 2];
392 P1
= P
[lower_half
+ 3];
396 *sg_output_plane
++ = P1
;
398 *sg_output_plane
++ = P0
;
400 sg_output_plane
+= sg_line_inc
;
405 /* need 10 more bytes */
406 CHECK_STREAM_PTR(10);
407 B
[0] = *sg_stream_ptr
++; B
[1] = *sg_stream_ptr
++;
408 B
[2] = *sg_stream_ptr
++; B
[3] = *sg_stream_ptr
++;
409 P
[2] = *sg_stream_ptr
++; P
[3] = *sg_stream_ptr
++;
410 B
[4] = *sg_stream_ptr
++; B
[5] = *sg_stream_ptr
++;
411 B
[6] = *sg_stream_ptr
++; B
[7] = *sg_stream_ptr
++;
415 /* vertical split; left & right halves are 2-color encoded */
417 for (y
= 0; y
< 8; y
++) {
419 /* time to reload flags? */
422 ((B
[0] & 0xF0) << 24) | ((B
[4] & 0xF0) << 20) |
423 ((B
[0] & 0x0F) << 20) | ((B
[4] & 0x0F) << 16) |
424 ((B
[1] & 0xF0) << 8) | ((B
[5] & 0xF0) << 4) |
425 ((B
[1] & 0x0F) << 4) | ((B
[5] & 0x0F) << 0);
426 bitmask
= 0x80000000;
429 ((B
[2] & 0xF0) << 24) | ((B
[6] & 0xF0) << 20) |
430 ((B
[2] & 0x0F) << 20) | ((B
[6] & 0x0F) << 16) |
431 ((B
[3] & 0xF0) << 8) | ((B
[7] & 0xF0) << 4) |
432 ((B
[3] & 0x0F) << 4) | ((B
[7] & 0x0F) << 0);
433 bitmask
= 0x80000000;
436 for (x
= 0; x
< 8; x
++, bitmask
>>= 1) {
437 /* get the pixel values ready for this half */
447 *sg_output_plane
++ = P0
;
449 *sg_output_plane
++ = P1
;
451 sg_output_plane
+= sg_line_inc
;
456 /* horizontal split; top & bottom halves are 2-color encoded */
458 for (y
= 0; y
< 8; y
++) {
469 for (bitmask
= 0x80; bitmask
!= 0; bitmask
>>= 1) {
472 *sg_output_plane
++ = P0
;
474 *sg_output_plane
++ = P1
;
476 sg_output_plane
+= sg_line_inc
;
485 static int ipvideo_decode_block_opcode_0x9(void)
489 unsigned int flags
= 0;
493 /* 4-color encoding */
496 for (y
= 0; y
< 4; y
++)
497 P
[y
] = *sg_stream_ptr
++;
499 if ((P
[0] <= P
[1]) && (P
[2] <= P
[3])) {
501 /* 1 of 4 colors for each pixel, need 16 more bytes */
502 CHECK_STREAM_PTR(16);
504 for (y
= 0; y
< 8; y
++) {
505 /* get the next set of 8 2-bit flags */
506 flags
= (sg_stream_ptr
[0] << 8) | sg_stream_ptr
[1];
508 for (x
= 0, shifter
= 14; x
< 8; x
++, shifter
-= 2) {
509 *sg_output_plane
++ = P
[(flags
>> shifter
) & 0x03];
511 sg_output_plane
+= sg_line_inc
;
514 } else if ((P
[0] <= P
[1]) && (P
[2] > P
[3])) {
516 /* 1 of 4 colors for each 2x2 block, need 4 more bytes */
520 flags
= (flags
<< 8) | *sg_stream_ptr
++;
521 flags
= (flags
<< 8) | *sg_stream_ptr
++;
522 flags
= (flags
<< 8) | *sg_stream_ptr
++;
523 flags
= (flags
<< 8) | *sg_stream_ptr
++;
526 for (y
= 0; y
< 8; y
+= 2) {
527 for (x
= 0; x
< 8; x
+= 2, shifter
-= 2) {
528 pix
= P
[(flags
>> shifter
) & 0x03];
529 *(sg_output_plane
+ x
) = pix
;
530 *(sg_output_plane
+ x
+ 1) = pix
;
531 *(sg_output_plane
+ sg_stride
+ x
) = pix
;
532 *(sg_output_plane
+ sg_stride
+ x
+ 1) = pix
;
534 sg_output_plane
+= sg_stride
* 2;
537 } else if ((P
[0] > P
[1]) && (P
[2] <= P
[3])) {
539 /* 1 of 4 colors for each 2x1 block, need 8 more bytes */
542 for (y
= 0; y
< 8; y
++) {
543 /* time to reload flags? */
544 if ((y
== 0) || (y
== 4)) {
546 flags
= (flags
<< 8) | *sg_stream_ptr
++;
547 flags
= (flags
<< 8) | *sg_stream_ptr
++;
548 flags
= (flags
<< 8) | *sg_stream_ptr
++;
549 flags
= (flags
<< 8) | *sg_stream_ptr
++;
552 for (x
= 0; x
< 8; x
+= 2, shifter
-= 2) {
553 pix
= P
[(flags
>> shifter
) & 0x03];
554 *(sg_output_plane
+ x
) = pix
;
555 *(sg_output_plane
+ x
+ 1) = pix
;
557 sg_output_plane
+= sg_stride
;
562 /* 1 of 4 colors for each 1x2 block, need 8 more bytes */
565 for (y
= 0; y
< 8; y
+= 2) {
566 /* time to reload flags? */
567 if ((y
== 0) || (y
== 4)) {
569 flags
= (flags
<< 8) | *sg_stream_ptr
++;
570 flags
= (flags
<< 8) | *sg_stream_ptr
++;
571 flags
= (flags
<< 8) | *sg_stream_ptr
++;
572 flags
= (flags
<< 8) | *sg_stream_ptr
++;
575 for (x
= 0; x
< 8; x
++, shifter
-= 2) {
576 pix
= P
[(flags
>> shifter
) & 0x03];
577 *(sg_output_plane
+ x
) = pix
;
578 *(sg_output_plane
+ sg_stride
+ x
) = pix
;
580 sg_output_plane
+= sg_stride
* 2;
588 static int ipvideo_decode_block_opcode_0xA(void)
599 /* 4-color encoding for each 4x4 quadrant, or 4-color encoding on
600 * either top and bottom or left and right halves */
603 for (y
= 0; y
< 4; y
++)
604 P
[y
] = *sg_stream_ptr
++;
608 /* 4-color encoding for each quadrant; need 28 more bytes */
609 CHECK_STREAM_PTR(28);
611 for (y
= 0; y
< 4; y
++)
612 B
[y
] = *sg_stream_ptr
++;
613 for (y
= 4; y
< 16; y
+= 4) {
614 for (x
= y
; x
< y
+ 4; x
++)
615 P
[x
] = *sg_stream_ptr
++;
616 for (x
= y
; x
< y
+ 4; x
++)
617 B
[x
] = *sg_stream_ptr
++;
620 for (y
= 0; y
< 8; y
++) {
622 lower_half
= (y
>= 4) ?
4 : 0;
623 flags
= (B
[y
] << 8) | B
[y
+ 8];
625 for (x
= 0, shifter
= 14; x
< 8; x
++, shifter
-= 2) {
626 split
= (x
>= 4) ?
8 : 0;
627 index
= split
+ lower_half
+ ((flags
>> shifter
) & 0x03);
628 *sg_output_plane
++ = P
[index
];
631 sg_output_plane
+= sg_line_inc
;
636 /* 4-color encoding for either left and right or top and bottom
637 * halves; need 20 more bytes */
638 CHECK_STREAM_PTR(20);
640 for (y
= 0; y
< 8; y
++)
641 B
[y
] = *sg_stream_ptr
++;
642 for (y
= 4; y
< 8; y
++)
643 P
[y
] = *sg_stream_ptr
++;
644 for (y
= 8; y
< 16; y
++)
645 B
[y
] = *sg_stream_ptr
++;
649 /* block is divided into left and right halves */
650 for (y
= 0; y
< 8; y
++) {
652 flags
= (B
[y
] << 8) | B
[y
+ 8];
655 for (x
= 0, shifter
= 14; x
< 8; x
++, shifter
-= 2) {
658 *sg_output_plane
++ = P
[split
+ ((flags
>> shifter
) & 0x03)];
661 sg_output_plane
+= sg_line_inc
;
666 /* block is divided into top and bottom halves */
668 for (y
= 0; y
< 8; y
++) {
670 flags
= (B
[y
* 2] << 8) | B
[y
* 2 + 1];
674 for (x
= 0, shifter
= 14; x
< 8; x
++, shifter
-= 2)
675 *sg_output_plane
++ = P
[split
+ ((flags
>> shifter
) & 0x03)];
677 sg_output_plane
+= sg_line_inc
;
686 static int ipvideo_decode_block_opcode_0xB(void)
690 /* 64-color encoding (each pixel in block is a different color) */
691 CHECK_STREAM_PTR(64);
693 for (y
= 0; y
< 8; y
++) {
694 for (x
= 0; x
< 8; x
++) {
695 *sg_output_plane
++ = *sg_stream_ptr
++;
697 sg_output_plane
+= sg_line_inc
;
704 static int ipvideo_decode_block_opcode_0xC(void)
709 /* 16-color block encoding: each 2x2 block is a different color */
710 CHECK_STREAM_PTR(16);
712 for (y
= 0; y
< 8; y
+= 2) {
713 for (x
= 0; x
< 8; x
+= 2) {
714 pix
= *sg_stream_ptr
++;
715 *(sg_output_plane
+ x
) = pix
;
716 *(sg_output_plane
+ x
+ 1) = pix
;
717 *(sg_output_plane
+ sg_stride
+ x
) = pix
;
718 *(sg_output_plane
+ sg_stride
+ x
+ 1) = pix
;
720 sg_output_plane
+= sg_stride
* 2;
727 static int ipvideo_decode_block_opcode_0xD(void)
731 unsigned char index
= 0;
733 /* 4-color block encoding: each 4x4 block is a different color */
736 for (y
= 0; y
< 4; y
++)
737 P
[y
] = *sg_stream_ptr
++;
739 for (y
= 0; y
< 8; y
++) {
745 for (x
= 0; x
< 8; x
++) {
748 *sg_output_plane
++ = P
[index
];
750 sg_output_plane
+= sg_line_inc
;
757 static int ipvideo_decode_block_opcode_0xE(void)
762 /* 1-color encoding: the whole block is 1 solid color */
764 pix
= *sg_stream_ptr
++;
766 for (y
= 0; y
< 8; y
++) {
767 for (x
= 0; x
< 8; x
++) {
768 *sg_output_plane
++ = pix
;
770 sg_output_plane
+= sg_line_inc
;
777 static int ipvideo_decode_block_opcode_0xF(void)
780 unsigned char sample0
, sample1
;
782 /* dithered encoding */
784 sample0
= *sg_stream_ptr
++;
785 sample1
= *sg_stream_ptr
++;
787 for (y
= 0; y
< 8; y
++) {
788 for (x
= 0; x
< 8; x
+= 2) {
790 *sg_output_plane
++ = sample1
;
791 *sg_output_plane
++ = sample0
;
793 *sg_output_plane
++ = sample0
;
794 *sg_output_plane
++ = sample1
;
797 sg_output_plane
+= sg_line_inc
;
804 static int (*ipvideo_decode_block
[16])(void);
806 static void ipvideo_decode_opcodes(IpvideoContext
*s
)
810 unsigned char opcode
;
813 static int frame
= 0;
815 debug_interplay("------------------ frame %d\n", frame
);
818 for (x
= 0; x
< 16; x
++)
821 /* this is PAL8, so make the palette available */
822 if (s
->avctx
->pix_fmt
== PIX_FMT_PAL8
)
823 memcpy(s
->current_frame
.data
[1], s
->palette
, PALETTE_COUNT
* 4);
825 switch (s
->avctx
->pix_fmt
) {
828 sg_stride
= s
->current_frame
.linesize
[0];
829 sg_stream_ptr
= s
->buf
+ 14; /* data starts 14 bytes in */
830 sg_stream_end
= s
->buf
+ s
->size
;
831 sg_line_inc
= sg_stride
- 8;
832 sg_current_plane
= s
->current_frame
.data
[0];
833 sg_last_plane
= s
->last_frame
.data
[0];
834 sg_upper_motion_limit_offset
= (s
->avctx
->height
- 8) * sg_stride
835 + s
->avctx
->width
- 8;
838 for (y
= 0; y
< (sg_stride
* s
->avctx
->height
); y
+= sg_stride
* 8) {
839 for (x
= y
; x
< y
+ s
->avctx
->width
; x
+= 8) {
840 /* bottom nibble first, then top nibble (which makes it
841 * hard to use a GetBitcontext) */
843 opcode
= s
->decoding_map
[index
>> 1] >> 4;
845 opcode
= s
->decoding_map
[index
>> 1] & 0xF;
848 debug_interplay(" block @ (%3d, %3d): encoding 0x%X, data ptr @ %p\n",
849 x
- y
, y
/ sg_stride
, opcode
, sg_stream_ptr
);
850 code_counts
[opcode
]++;
852 sg_output_plane
= sg_current_plane
+ x
;
853 ret
= ipvideo_decode_block
[opcode
]();
855 printf(" Interplay video: decode problem on frame %d, @ block (%d, %d)\n",
856 frame
, x
- y
, y
/ sg_stride
);
861 if ((sg_stream_ptr
!= sg_stream_end
) &&
862 (sg_stream_ptr
+ 1 != sg_stream_end
)) {
863 printf (" Interplay video: decode finished with %d bytes left over\n",
864 sg_stream_end
- sg_stream_ptr
);
869 printf ("Interplay video: Unhandled video format\n");
875 static int ipvideo_decode_init(AVCodecContext
*avctx
)
877 IpvideoContext
*s
= avctx
->priv_data
;
881 if (s
->avctx
->extradata_size
!= sizeof(AVPaletteControl
)) {
882 printf (" Interplay video: expected extradata_size of %d\n",
883 sizeof(AVPaletteControl
));
887 avctx
->pix_fmt
= PIX_FMT_PAL8
;
888 avctx
->has_b_frames
= 0;
889 dsputil_init(&s
->dsp
, avctx
);
893 /* decoding map contains 4 bits of information per 8x8 block */
894 s
->decoding_map_size
= avctx
->width
* avctx
->height
/ (8 * 8 * 2);
896 /* assign block decode functions */
897 ipvideo_decode_block
[0x0] = ipvideo_decode_block_opcode_0x0_0x1
;
898 ipvideo_decode_block
[0x1] = ipvideo_decode_block_opcode_0x0_0x1
;
899 ipvideo_decode_block
[0x2] = ipvideo_decode_block_opcode_0x2
;
900 ipvideo_decode_block
[0x3] = ipvideo_decode_block_opcode_0x3
;
901 ipvideo_decode_block
[0x4] = ipvideo_decode_block_opcode_0x4
;
902 ipvideo_decode_block
[0x5] = ipvideo_decode_block_opcode_0x5
;
903 ipvideo_decode_block
[0x6] = ipvideo_decode_block_opcode_0x6
;
904 ipvideo_decode_block
[0x7] = ipvideo_decode_block_opcode_0x7
;
905 ipvideo_decode_block
[0x8] = ipvideo_decode_block_opcode_0x8
;
906 ipvideo_decode_block
[0x9] = ipvideo_decode_block_opcode_0x9
;
907 ipvideo_decode_block
[0xA] = ipvideo_decode_block_opcode_0xA
;
908 ipvideo_decode_block
[0xB] = ipvideo_decode_block_opcode_0xB
;
909 ipvideo_decode_block
[0xC] = ipvideo_decode_block_opcode_0xC
;
910 ipvideo_decode_block
[0xD] = ipvideo_decode_block_opcode_0xD
;
911 ipvideo_decode_block
[0xE] = ipvideo_decode_block_opcode_0xE
;
912 ipvideo_decode_block
[0xF] = ipvideo_decode_block_opcode_0xF
;
917 static int ipvideo_decode_frame(AVCodecContext
*avctx
,
918 void *data
, int *data_size
,
919 uint8_t *buf
, int buf_size
)
921 IpvideoContext
*s
= avctx
->priv_data
;
922 AVPaletteControl
*palette_control
= (AVPaletteControl
*)avctx
->extradata
;
924 if (palette_control
->palette_changed
) {
925 /* load the new palette and reset the palette control */
926 ipvideo_new_palette(s
, palette_control
->palette
);
927 palette_control
->palette_changed
= 0;
930 s
->decoding_map
= buf
;
931 s
->buf
= buf
+ s
->decoding_map_size
;
932 s
->size
= buf_size
- s
->decoding_map_size
;
934 if (avctx
->get_buffer(avctx
, &s
->current_frame
)) {
935 printf (" Interplay Video: get_buffer() failed\n");
939 ipvideo_decode_opcodes(s
);
941 /* release the last frame if it is allocated */
945 avctx
->release_buffer(avctx
, &s
->last_frame
);
948 s
->last_frame
= s
->current_frame
;
950 *data_size
= sizeof(AVFrame
);
951 *(AVFrame
*)data
= s
->current_frame
;
953 /* report that the buffer was completely consumed */
957 static int ipvideo_decode_end(AVCodecContext
*avctx
)
959 IpvideoContext
*s
= avctx
->priv_data
;
961 /* release the last frame */
962 avctx
->release_buffer(avctx
, &s
->last_frame
);
967 AVCodec interplay_video_decoder
= {
970 CODEC_ID_INTERPLAY_VIDEO
,
971 sizeof(IpvideoContext
),
975 ipvideo_decode_frame
,