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"
38 #include "bytestream.h"
39 #define ALT_BITSTREAM_READER_LE
41 // for av_memcpy_backptr
42 #include "libavutil/lzo.h"
44 typedef struct XanContext
{
46 AVCodecContext
*avctx
;
48 AVFrame current_frame
;
50 const unsigned char *buf
;
54 unsigned char *buffer1
;
56 unsigned char *buffer2
;
63 static av_cold
int xan_decode_init(AVCodecContext
*avctx
)
65 XanContext
*s
= avctx
->priv_data
;
70 if ((avctx
->codec
->id
== CODEC_ID_XAN_WC3
) &&
71 (s
->avctx
->palctrl
== NULL
)) {
72 av_log(avctx
, AV_LOG_ERROR
, " WC3 Xan video: palette expected.\n");
76 avctx
->pix_fmt
= PIX_FMT_PAL8
;
78 if(avcodec_check_dimensions(avctx
, avctx
->width
, avctx
->height
))
81 s
->buffer1_size
= avctx
->width
* avctx
->height
;
82 s
->buffer1
= av_malloc(s
->buffer1_size
);
83 s
->buffer2_size
= avctx
->width
* avctx
->height
;
84 s
->buffer2
= av_malloc(s
->buffer2_size
+ 130);
85 if (!s
->buffer1
|| !s
->buffer2
)
91 static int xan_huffman_decode(unsigned char *dest
, const unsigned char *src
,
94 unsigned char byte
= *src
++;
95 unsigned char ival
= byte
+ 0x16;
96 const unsigned char * ptr
= src
+ byte
*2;
97 unsigned char val
= ival
;
98 unsigned char *dest_end
= dest
+ dest_len
;
101 init_get_bits(&gb
, ptr
, 0); // FIXME: no src size available
103 while ( val
!= 0x16 ) {
104 val
= src
[val
- 0x17 + get_bits1(&gb
) * byte
];
107 if (dest
>= dest_end
)
118 * unpack simple compression
120 * @param dest destination buffer of dest_len, must be padded with at least 130 bytes
122 static void xan_unpack(unsigned char *dest
, const unsigned char *src
, int dest_len
)
124 unsigned char opcode
;
126 unsigned char *dest_end
= dest
+ dest_len
;
128 while (dest
< dest_end
) {
133 if ( (opcode
& 0x80) == 0 ) {
137 back
= ((opcode
& 0x60) << 3) + *src
++ + 1;
138 size2
= ((opcode
& 0x1c) >> 2) + 3;
140 } else if ( (opcode
& 0x40) == 0 ) {
144 back
= (bytestream_get_be16(&src
) & 0x3fff) + 1;
145 size2
= (opcode
& 0x3f) + 4;
151 back
= ((opcode
& 0x10) << 12) + bytestream_get_be16(&src
) + 1;
152 size2
= ((opcode
& 0x0c) << 6) + *src
++ + 5;
153 if (size
+ size2
> dest_end
- dest
)
156 memcpy(dest
, src
, size
); dest
+= size
; src
+= size
;
157 av_memcpy_backptr(dest
, back
, size2
);
161 size
= ((opcode
& 0x1f) << 2) + 4;
163 finish
= size
> 0x70;
167 memcpy(dest
, src
, size
); dest
+= size
; src
+= size
;
174 static inline void xan_wc3_output_pixel_run(XanContext
*s
,
175 const unsigned char *pixel_buffer
, int x
, int y
, int pixel_count
)
181 int width
= s
->avctx
->width
;
182 unsigned char *palette_plane
;
184 palette_plane
= s
->current_frame
.data
[0];
185 stride
= s
->current_frame
.linesize
[0];
186 line_inc
= stride
- width
;
187 index
= y
* stride
+ x
;
189 while((pixel_count
--) && (index
< s
->frame_size
)) {
191 /* don't do a memcpy() here; keyframes generally copy an entire
192 * frame of data and the stride needs to be accounted for */
193 palette_plane
[index
++] = *pixel_buffer
++;
196 if (current_x
>= width
) {
203 static inline void xan_wc3_copy_pixel_run(XanContext
*s
,
204 int x
, int y
, int pixel_count
, int motion_x
, int motion_y
)
208 int curframe_index
, prevframe_index
;
209 int curframe_x
, prevframe_x
;
210 int width
= s
->avctx
->width
;
211 unsigned char *palette_plane
, *prev_palette_plane
;
213 palette_plane
= s
->current_frame
.data
[0];
214 prev_palette_plane
= s
->last_frame
.data
[0];
215 stride
= s
->current_frame
.linesize
[0];
216 line_inc
= stride
- width
;
217 curframe_index
= y
* stride
+ x
;
219 prevframe_index
= (y
+ motion_y
) * stride
+ x
+ motion_x
;
220 prevframe_x
= x
+ motion_x
;
221 while((pixel_count
--) && (curframe_index
< s
->frame_size
)) {
223 palette_plane
[curframe_index
++] =
224 prev_palette_plane
[prevframe_index
++];
227 if (curframe_x
>= width
) {
228 curframe_index
+= line_inc
;
233 if (prevframe_x
>= width
) {
234 prevframe_index
+= line_inc
;
240 static void xan_wc3_decode_frame(XanContext
*s
) {
242 int width
= s
->avctx
->width
;
243 int height
= s
->avctx
->height
;
244 int total_pixels
= width
* height
;
245 unsigned char opcode
;
246 unsigned char flag
= 0;
248 int motion_x
, motion_y
;
251 unsigned char *opcode_buffer
= s
->buffer1
;
252 int opcode_buffer_size
= s
->buffer1_size
;
253 const unsigned char *imagedata_buffer
= s
->buffer2
;
255 /* pointers to segments inside the compressed chunk */
256 const unsigned char *huffman_segment
;
257 const unsigned char *size_segment
;
258 const unsigned char *vector_segment
;
259 const unsigned char *imagedata_segment
;
261 huffman_segment
= s
->buf
+ AV_RL16(&s
->buf
[0]);
262 size_segment
= s
->buf
+ AV_RL16(&s
->buf
[2]);
263 vector_segment
= s
->buf
+ AV_RL16(&s
->buf
[4]);
264 imagedata_segment
= s
->buf
+ AV_RL16(&s
->buf
[6]);
266 xan_huffman_decode(opcode_buffer
, huffman_segment
, opcode_buffer_size
);
268 if (imagedata_segment
[0] == 2)
269 xan_unpack(s
->buffer2
, &imagedata_segment
[1], s
->buffer2_size
);
271 imagedata_buffer
= &imagedata_segment
[1];
273 /* use the decoded data segments to build the frame */
275 while (total_pixels
) {
277 opcode
= *opcode_buffer
++;
304 size
+= (opcode
- 10);
309 size
= *size_segment
++;
314 size
= AV_RB16(&size_segment
[0]);
320 size
= AV_RB24(size_segment
);
328 /* run of (size) pixels is unchanged from last frame */
329 xan_wc3_copy_pixel_run(s
, x
, y
, size
, 0, 0);
331 /* output a run of pixels from imagedata_buffer */
332 xan_wc3_output_pixel_run(s
, imagedata_buffer
, x
, y
, size
);
333 imagedata_buffer
+= size
;
336 /* run-based motion compensation from last frame */
337 motion_x
= sign_extend(*vector_segment
>> 4, 4);
338 motion_y
= sign_extend(*vector_segment
& 0xF, 4);
341 /* copy a run of pixels from the previous frame */
342 xan_wc3_copy_pixel_run(s
, x
, y
, size
, motion_x
, motion_y
);
347 /* coordinate accounting */
348 total_pixels
-= size
;
349 y
+= (x
+ size
) / width
;
350 x
= (x
+ size
) % width
;
354 static void xan_wc4_decode_frame(XanContext
*s
) {
357 static int xan_decode_frame(AVCodecContext
*avctx
,
358 void *data
, int *data_size
,
361 const uint8_t *buf
= avpkt
->data
;
362 int buf_size
= avpkt
->size
;
363 XanContext
*s
= avctx
->priv_data
;
364 AVPaletteControl
*palette_control
= avctx
->palctrl
;
366 if (avctx
->get_buffer(avctx
, &s
->current_frame
)) {
367 av_log(s
->avctx
, AV_LOG_ERROR
, " Xan Video: get_buffer() failed\n");
370 s
->current_frame
.reference
= 3;
373 s
->frame_size
= s
->current_frame
.linesize
[0] * s
->avctx
->height
;
375 palette_control
->palette_changed
= 0;
376 memcpy(s
->current_frame
.data
[1], palette_control
->palette
,
378 s
->current_frame
.palette_has_changed
= 1;
383 if (avctx
->codec
->id
== CODEC_ID_XAN_WC3
)
384 xan_wc3_decode_frame(s
);
385 else if (avctx
->codec
->id
== CODEC_ID_XAN_WC4
)
386 xan_wc4_decode_frame(s
);
388 /* release the last frame if it is allocated */
389 if (s
->last_frame
.data
[0])
390 avctx
->release_buffer(avctx
, &s
->last_frame
);
392 *data_size
= sizeof(AVFrame
);
393 *(AVFrame
*)data
= s
->current_frame
;
396 FFSWAP(AVFrame
, s
->current_frame
, s
->last_frame
);
398 /* always report that the buffer was completely consumed */
402 static av_cold
int xan_decode_end(AVCodecContext
*avctx
)
404 XanContext
*s
= avctx
->priv_data
;
406 /* release the frames */
407 if (s
->last_frame
.data
[0])
408 avctx
->release_buffer(avctx
, &s
->last_frame
);
409 if (s
->current_frame
.data
[0])
410 avctx
->release_buffer(avctx
, &s
->current_frame
);
418 AVCodec xan_wc3_decoder
= {
428 .long_name
= NULL_IF_CONFIG_SMALL("Wing Commander III / Xan"),
432 AVCodec xan_wc4_decoder = {