2 * Wing Commander/Xan 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/xan.c
24 * Xan video decoder for Wing Commander III computer game
25 * by Mario Brito (mbrito@student.dei.uc.pt)
26 * and Mike Melanson (melanson@pcisys.net)
28 * The xan_wc3 decoder outputs PAL8 data.
36 #include "libavutil/intreadwrite.h"
39 typedef struct XanContext
{
41 AVCodecContext
*avctx
;
43 AVFrame current_frame
;
45 const unsigned char *buf
;
49 unsigned char *buffer1
;
51 unsigned char *buffer2
;
58 static av_cold
int xan_decode_init(AVCodecContext
*avctx
)
60 XanContext
*s
= avctx
->priv_data
;
65 if ((avctx
->codec
->id
== CODEC_ID_XAN_WC3
) &&
66 (s
->avctx
->palctrl
== NULL
)) {
67 av_log(avctx
, AV_LOG_ERROR
, " WC3 Xan video: palette expected.\n");
71 avctx
->pix_fmt
= PIX_FMT_PAL8
;
73 if(avcodec_check_dimensions(avctx
, avctx
->width
, avctx
->height
))
76 s
->buffer1_size
= avctx
->width
* avctx
->height
;
77 s
->buffer1
= av_malloc(s
->buffer1_size
);
78 s
->buffer2_size
= avctx
->width
* avctx
->height
;
79 s
->buffer2
= av_malloc(s
->buffer2_size
);
80 if (!s
->buffer1
|| !s
->buffer2
)
86 /* This function is used in lieu of memcpy(). This decoder cannot use
87 * memcpy because the memory locations often overlap and
88 * memcpy doesn't like that; it's not uncommon, for example, for
89 * dest = src+1, to turn byte A into pattern AAAAAAAA.
90 * This was originally repz movsb in Intel x86 ASM. */
91 static inline void bytecopy(unsigned char *dest
, const unsigned char *src
, int count
)
95 for (i
= 0; i
< count
; i
++)
99 static int xan_huffman_decode(unsigned char *dest
, const unsigned char *src
,
102 unsigned char byte
= *src
++;
103 unsigned char ival
= byte
+ 0x16;
104 const unsigned char * ptr
= src
+ byte
*2;
105 unsigned char val
= ival
;
107 unsigned char *dest_end
= dest
+ dest_len
;
109 unsigned char bits
= *ptr
++;
111 while ( val
!= 0x16 ) {
112 if ( (1 << counter
) & bits
)
113 val
= src
[byte
+ val
- 0x17];
115 val
= src
[val
- 0x17];
118 if (dest
+ 1 > dest_end
)
124 if (counter
++ == 7) {
133 static void xan_unpack(unsigned char *dest
, const unsigned char *src
, int dest_len
)
135 unsigned char opcode
;
138 int byte1
, byte2
, byte3
;
139 unsigned char *dest_end
= dest
+ dest_len
;
144 if ( (opcode
& 0x80) == 0 ) {
149 if (dest
+ size
> dest_end
)
151 bytecopy(dest
, src
, size
); dest
+= size
; src
+= size
;
153 size
= ((opcode
& 0x1c) >> 2) + 3;
154 if (dest
+ size
> dest_end
)
156 bytecopy (dest
, dest
- (((opcode
& 0x60) << 3) + offset
+ 1), size
);
159 } else if ( (opcode
& 0x40) == 0 ) {
165 if (dest
+ size
> dest_end
)
167 bytecopy (dest
, src
, size
); dest
+= size
; src
+= size
;
169 size
= (opcode
& 0x3f) + 4;
170 if (dest
+ size
> dest_end
)
172 bytecopy (dest
, dest
- (((byte1
& 0x3f) << 8) + byte2
+ 1), size
);
175 } else if ( (opcode
& 0x20) == 0 ) {
182 if (dest
+ size
> dest_end
)
184 bytecopy (dest
, src
, size
); dest
+= size
; src
+= size
;
186 size
= byte3
+ 5 + ((opcode
& 0xc) << 6);
187 if (dest
+ size
> dest_end
)
190 dest
- ((((opcode
& 0x10) >> 4) << 0x10) + 1 + (byte1
<< 8) + byte2
),
194 size
= ((opcode
& 0x1f) << 2) + 4;
199 if (dest
+ size
> dest_end
)
201 bytecopy (dest
, src
, size
); dest
+= size
; src
+= size
;
206 bytecopy(dest
, src
, size
); dest
+= size
; src
+= size
;
209 static inline void xan_wc3_output_pixel_run(XanContext
*s
,
210 const unsigned char *pixel_buffer
, int x
, int y
, int pixel_count
)
216 int width
= s
->avctx
->width
;
217 unsigned char *palette_plane
;
219 palette_plane
= s
->current_frame
.data
[0];
220 stride
= s
->current_frame
.linesize
[0];
221 line_inc
= stride
- width
;
222 index
= y
* stride
+ x
;
224 while((pixel_count
--) && (index
< s
->frame_size
)) {
226 /* don't do a memcpy() here; keyframes generally copy an entire
227 * frame of data and the stride needs to be accounted for */
228 palette_plane
[index
++] = *pixel_buffer
++;
231 if (current_x
>= width
) {
238 static inline void xan_wc3_copy_pixel_run(XanContext
*s
,
239 int x
, int y
, int pixel_count
, int motion_x
, int motion_y
)
243 int curframe_index
, prevframe_index
;
244 int curframe_x
, prevframe_x
;
245 int width
= s
->avctx
->width
;
246 unsigned char *palette_plane
, *prev_palette_plane
;
248 palette_plane
= s
->current_frame
.data
[0];
249 prev_palette_plane
= s
->last_frame
.data
[0];
250 stride
= s
->current_frame
.linesize
[0];
251 line_inc
= stride
- width
;
252 curframe_index
= y
* stride
+ x
;
254 prevframe_index
= (y
+ motion_y
) * stride
+ x
+ motion_x
;
255 prevframe_x
= x
+ motion_x
;
256 while((pixel_count
--) && (curframe_index
< s
->frame_size
)) {
258 palette_plane
[curframe_index
++] =
259 prev_palette_plane
[prevframe_index
++];
262 if (curframe_x
>= width
) {
263 curframe_index
+= line_inc
;
268 if (prevframe_x
>= width
) {
269 prevframe_index
+= line_inc
;
275 static void xan_wc3_decode_frame(XanContext
*s
) {
277 int width
= s
->avctx
->width
;
278 int height
= s
->avctx
->height
;
279 int total_pixels
= width
* height
;
280 unsigned char opcode
;
281 unsigned char flag
= 0;
283 int motion_x
, motion_y
;
286 unsigned char *opcode_buffer
= s
->buffer1
;
287 int opcode_buffer_size
= s
->buffer1_size
;
288 const unsigned char *imagedata_buffer
= s
->buffer2
;
290 /* pointers to segments inside the compressed chunk */
291 const unsigned char *huffman_segment
;
292 const unsigned char *size_segment
;
293 const unsigned char *vector_segment
;
294 const unsigned char *imagedata_segment
;
296 huffman_segment
= s
->buf
+ AV_RL16(&s
->buf
[0]);
297 size_segment
= s
->buf
+ AV_RL16(&s
->buf
[2]);
298 vector_segment
= s
->buf
+ AV_RL16(&s
->buf
[4]);
299 imagedata_segment
= s
->buf
+ AV_RL16(&s
->buf
[6]);
301 xan_huffman_decode(opcode_buffer
, huffman_segment
, opcode_buffer_size
);
303 if (imagedata_segment
[0] == 2)
304 xan_unpack(s
->buffer2
, &imagedata_segment
[1], s
->buffer2_size
);
306 imagedata_buffer
= &imagedata_segment
[1];
308 /* use the decoded data segments to build the frame */
310 while (total_pixels
) {
312 opcode
= *opcode_buffer
++;
339 size
+= (opcode
- 10);
344 size
= *size_segment
++;
349 size
= AV_RB16(&size_segment
[0]);
355 size
= AV_RB24(size_segment
);
363 /* run of (size) pixels is unchanged from last frame */
364 xan_wc3_copy_pixel_run(s
, x
, y
, size
, 0, 0);
366 /* output a run of pixels from imagedata_buffer */
367 xan_wc3_output_pixel_run(s
, imagedata_buffer
, x
, y
, size
);
368 imagedata_buffer
+= size
;
371 /* run-based motion compensation from last frame */
372 motion_x
= (*vector_segment
>> 4) & 0xF;
373 motion_y
= *vector_segment
& 0xF;
378 motion_x
|= 0xFFFFFFF0;
380 motion_y
|= 0xFFFFFFF0;
382 /* copy a run of pixels from the previous frame */
383 xan_wc3_copy_pixel_run(s
, x
, y
, size
, motion_x
, motion_y
);
388 /* coordinate accounting */
389 total_pixels
-= size
;
391 if (x
+ size
>= width
) {
403 static void xan_wc4_decode_frame(XanContext
*s
) {
406 static int xan_decode_frame(AVCodecContext
*avctx
,
407 void *data
, int *data_size
,
408 const uint8_t *buf
, int buf_size
)
410 XanContext
*s
= avctx
->priv_data
;
411 AVPaletteControl
*palette_control
= avctx
->palctrl
;
413 if (avctx
->get_buffer(avctx
, &s
->current_frame
)) {
414 av_log(s
->avctx
, AV_LOG_ERROR
, " Xan Video: get_buffer() failed\n");
417 s
->current_frame
.reference
= 3;
420 s
->frame_size
= s
->current_frame
.linesize
[0] * s
->avctx
->height
;
422 palette_control
->palette_changed
= 0;
423 memcpy(s
->current_frame
.data
[1], palette_control
->palette
,
425 s
->current_frame
.palette_has_changed
= 1;
430 if (avctx
->codec
->id
== CODEC_ID_XAN_WC3
)
431 xan_wc3_decode_frame(s
);
432 else if (avctx
->codec
->id
== CODEC_ID_XAN_WC4
)
433 xan_wc4_decode_frame(s
);
435 /* release the last frame if it is allocated */
436 if (s
->last_frame
.data
[0])
437 avctx
->release_buffer(avctx
, &s
->last_frame
);
439 *data_size
= sizeof(AVFrame
);
440 *(AVFrame
*)data
= s
->current_frame
;
443 FFSWAP(AVFrame
, s
->current_frame
, s
->last_frame
);
445 /* always report that the buffer was completely consumed */
449 static av_cold
int xan_decode_end(AVCodecContext
*avctx
)
451 XanContext
*s
= avctx
->priv_data
;
453 /* release the frames */
454 if (s
->last_frame
.data
[0])
455 avctx
->release_buffer(avctx
, &s
->last_frame
);
456 if (s
->current_frame
.data
[0])
457 avctx
->release_buffer(avctx
, &s
->current_frame
);
465 AVCodec xan_wc3_decoder
= {
475 .long_name
= NULL_IF_CONFIG_SMALL("Wing Commander III / Xan"),
479 AVCodec xan_wc4_decoder = {