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.
35 #include "libavutil/intreadwrite.h"
37 #include "bytestream.h"
38 #define ALT_BITSTREAM_READER_LE
40 // for av_memcpy_backptr
41 #include "libavutil/lzo.h"
43 typedef struct XanContext
{
45 AVCodecContext
*avctx
;
47 AVFrame current_frame
;
49 const unsigned char *buf
;
53 unsigned char *buffer1
;
55 unsigned char *buffer2
;
62 static av_cold
int xan_decode_init(AVCodecContext
*avctx
)
64 XanContext
*s
= avctx
->priv_data
;
69 if ((avctx
->codec
->id
== CODEC_ID_XAN_WC3
) &&
70 (s
->avctx
->palctrl
== NULL
)) {
71 av_log(avctx
, AV_LOG_ERROR
, " WC3 Xan video: palette expected.\n");
75 avctx
->pix_fmt
= PIX_FMT_PAL8
;
77 if(avcodec_check_dimensions(avctx
, avctx
->width
, avctx
->height
))
80 s
->buffer1_size
= avctx
->width
* avctx
->height
;
81 s
->buffer1
= av_malloc(s
->buffer1_size
);
82 s
->buffer2_size
= avctx
->width
* avctx
->height
;
83 s
->buffer2
= av_malloc(s
->buffer2_size
+ 130);
84 if (!s
->buffer1
|| !s
->buffer2
)
90 static int xan_huffman_decode(unsigned char *dest
, const unsigned char *src
,
93 unsigned char byte
= *src
++;
94 unsigned char ival
= byte
+ 0x16;
95 const unsigned char * ptr
= src
+ byte
*2;
96 unsigned char val
= ival
;
97 unsigned char *dest_end
= dest
+ dest_len
;
100 init_get_bits(&gb
, ptr
, 0); // FIXME: no src size available
102 while ( val
!= 0x16 ) {
103 val
= src
[val
- 0x17 + get_bits1(&gb
) * byte
];
106 if (dest
>= dest_end
)
117 * unpack simple compression
119 * @param dest destination buffer of dest_len, must be padded with at least 130 bytes
121 static void xan_unpack(unsigned char *dest
, const unsigned char *src
, int dest_len
)
123 unsigned char opcode
;
125 unsigned char *dest_end
= dest
+ dest_len
;
127 while (dest
< dest_end
) {
132 if ( (opcode
& 0x80) == 0 ) {
136 back
= ((opcode
& 0x60) << 3) + *src
++ + 1;
137 size2
= ((opcode
& 0x1c) >> 2) + 3;
139 } else if ( (opcode
& 0x40) == 0 ) {
143 back
= (bytestream_get_be16(&src
) & 0x3fff) + 1;
144 size2
= (opcode
& 0x3f) + 4;
150 back
= ((opcode
& 0x10) << 12) + bytestream_get_be16(&src
) + 1;
151 size2
= ((opcode
& 0x0c) << 6) + *src
++ + 5;
152 if (size
+ size2
> dest_end
- dest
)
155 memcpy(dest
, src
, size
); dest
+= size
; src
+= size
;
156 av_memcpy_backptr(dest
, back
, size2
);
160 size
= ((opcode
& 0x1f) << 2) + 4;
162 finish
= size
> 0x70;
166 memcpy(dest
, src
, size
); dest
+= size
; src
+= size
;
173 static inline void xan_wc3_output_pixel_run(XanContext
*s
,
174 const unsigned char *pixel_buffer
, int x
, int y
, int pixel_count
)
180 int width
= s
->avctx
->width
;
181 unsigned char *palette_plane
;
183 palette_plane
= s
->current_frame
.data
[0];
184 stride
= s
->current_frame
.linesize
[0];
185 line_inc
= stride
- width
;
186 index
= y
* stride
+ x
;
188 while((pixel_count
--) && (index
< s
->frame_size
)) {
190 /* don't do a memcpy() here; keyframes generally copy an entire
191 * frame of data and the stride needs to be accounted for */
192 palette_plane
[index
++] = *pixel_buffer
++;
195 if (current_x
>= width
) {
202 static inline void xan_wc3_copy_pixel_run(XanContext
*s
,
203 int x
, int y
, int pixel_count
, int motion_x
, int motion_y
)
207 int curframe_index
, prevframe_index
;
208 int curframe_x
, prevframe_x
;
209 int width
= s
->avctx
->width
;
210 unsigned char *palette_plane
, *prev_palette_plane
;
212 palette_plane
= s
->current_frame
.data
[0];
213 prev_palette_plane
= s
->last_frame
.data
[0];
214 stride
= s
->current_frame
.linesize
[0];
215 line_inc
= stride
- width
;
216 curframe_index
= y
* stride
+ x
;
218 prevframe_index
= (y
+ motion_y
) * stride
+ x
+ motion_x
;
219 prevframe_x
= x
+ motion_x
;
220 while((pixel_count
--) && (curframe_index
< s
->frame_size
)) {
222 palette_plane
[curframe_index
++] =
223 prev_palette_plane
[prevframe_index
++];
226 if (curframe_x
>= width
) {
227 curframe_index
+= line_inc
;
232 if (prevframe_x
>= width
) {
233 prevframe_index
+= line_inc
;
239 static void xan_wc3_decode_frame(XanContext
*s
) {
241 int width
= s
->avctx
->width
;
242 int height
= s
->avctx
->height
;
243 int total_pixels
= width
* height
;
244 unsigned char opcode
;
245 unsigned char flag
= 0;
247 int motion_x
, motion_y
;
250 unsigned char *opcode_buffer
= s
->buffer1
;
251 int opcode_buffer_size
= s
->buffer1_size
;
252 const unsigned char *imagedata_buffer
= s
->buffer2
;
254 /* pointers to segments inside the compressed chunk */
255 const unsigned char *huffman_segment
;
256 const unsigned char *size_segment
;
257 const unsigned char *vector_segment
;
258 const unsigned char *imagedata_segment
;
260 huffman_segment
= s
->buf
+ AV_RL16(&s
->buf
[0]);
261 size_segment
= s
->buf
+ AV_RL16(&s
->buf
[2]);
262 vector_segment
= s
->buf
+ AV_RL16(&s
->buf
[4]);
263 imagedata_segment
= s
->buf
+ AV_RL16(&s
->buf
[6]);
265 xan_huffman_decode(opcode_buffer
, huffman_segment
, opcode_buffer_size
);
267 if (imagedata_segment
[0] == 2)
268 xan_unpack(s
->buffer2
, &imagedata_segment
[1], s
->buffer2_size
);
270 imagedata_buffer
= &imagedata_segment
[1];
272 /* use the decoded data segments to build the frame */
274 while (total_pixels
) {
276 opcode
= *opcode_buffer
++;
303 size
+= (opcode
- 10);
308 size
= *size_segment
++;
313 size
= AV_RB16(&size_segment
[0]);
319 size
= AV_RB24(size_segment
);
327 /* run of (size) pixels is unchanged from last frame */
328 xan_wc3_copy_pixel_run(s
, x
, y
, size
, 0, 0);
330 /* output a run of pixels from imagedata_buffer */
331 xan_wc3_output_pixel_run(s
, imagedata_buffer
, x
, y
, size
);
332 imagedata_buffer
+= size
;
335 /* run-based motion compensation from last frame */
336 motion_x
= sign_extend(*vector_segment
>> 4, 4);
337 motion_y
= sign_extend(*vector_segment
& 0xF, 4);
340 /* copy a run of pixels from the previous frame */
341 xan_wc3_copy_pixel_run(s
, x
, y
, size
, motion_x
, motion_y
);
346 /* coordinate accounting */
347 total_pixels
-= size
;
348 y
+= (x
+ size
) / width
;
349 x
= (x
+ size
) % width
;
353 static void xan_wc4_decode_frame(XanContext
*s
) {
356 static int xan_decode_frame(AVCodecContext
*avctx
,
357 void *data
, int *data_size
,
360 const uint8_t *buf
= avpkt
->data
;
361 int buf_size
= avpkt
->size
;
362 XanContext
*s
= avctx
->priv_data
;
363 AVPaletteControl
*palette_control
= avctx
->palctrl
;
365 if (avctx
->get_buffer(avctx
, &s
->current_frame
)) {
366 av_log(s
->avctx
, AV_LOG_ERROR
, " Xan Video: get_buffer() failed\n");
369 s
->current_frame
.reference
= 3;
372 s
->frame_size
= s
->current_frame
.linesize
[0] * s
->avctx
->height
;
374 palette_control
->palette_changed
= 0;
375 memcpy(s
->current_frame
.data
[1], palette_control
->palette
,
377 s
->current_frame
.palette_has_changed
= 1;
382 if (avctx
->codec
->id
== CODEC_ID_XAN_WC3
)
383 xan_wc3_decode_frame(s
);
384 else if (avctx
->codec
->id
== CODEC_ID_XAN_WC4
)
385 xan_wc4_decode_frame(s
);
387 /* release the last frame if it is allocated */
388 if (s
->last_frame
.data
[0])
389 avctx
->release_buffer(avctx
, &s
->last_frame
);
391 *data_size
= sizeof(AVFrame
);
392 *(AVFrame
*)data
= s
->current_frame
;
395 FFSWAP(AVFrame
, s
->current_frame
, s
->last_frame
);
397 /* always report that the buffer was completely consumed */
401 static av_cold
int xan_decode_end(AVCodecContext
*avctx
)
403 XanContext
*s
= avctx
->priv_data
;
405 /* release the frames */
406 if (s
->last_frame
.data
[0])
407 avctx
->release_buffer(avctx
, &s
->last_frame
);
408 if (s
->current_frame
.data
[0])
409 avctx
->release_buffer(avctx
, &s
->current_frame
);
417 AVCodec xan_wc3_decoder
= {
427 .long_name
= NULL_IF_CONFIG_SMALL("Wing Commander III / Xan"),
431 AVCodec xan_wc4_decoder = {