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
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 #define VGA__TAG MKTAG('V', 'G', 'A', ' ')
44 #define PALT_TAG MKTAG('P', 'A', 'L', 'T')
45 #define SHOT_TAG MKTAG('S', 'H', 'O', 'T')
46 #define PALETTE_COUNT 256
47 #define PALETTE_SIZE (PALETTE_COUNT * 3)
48 #define PALETTES_MAX 256
50 typedef struct XanContext {
52 AVCodecContext *avctx;
54 AVFrame current_frame;
56 const unsigned char *buf;
60 unsigned char *buffer1;
62 unsigned char *buffer2;
73 static av_cold int xan_decode_init(AVCodecContext *avctx)
75 XanContext *s = avctx->priv_data;
80 avctx->pix_fmt = PIX_FMT_PAL8;
82 s->buffer1_size = avctx->width * avctx->height;
83 s->buffer1 = av_malloc(s->buffer1_size);
85 return AVERROR(ENOMEM);
86 s->buffer2_size = avctx->width * avctx->height;
87 s->buffer2 = av_malloc(s->buffer2_size + 130);
89 av_freep(&s->buffer1);
90 return AVERROR(ENOMEM);
96 static int xan_huffman_decode(unsigned char *dest, const unsigned char *src,
99 unsigned char byte = *src++;
100 unsigned char ival = byte + 0x16;
101 const unsigned char * ptr = src + byte*2;
102 unsigned char val = ival;
103 unsigned char *dest_end = dest + dest_len;
106 init_get_bits(&gb, ptr, 0); // FIXME: no src size available
108 while ( val != 0x16 ) {
109 val = src[val - 0x17 + get_bits1(&gb) * byte];
112 if (dest >= dest_end)
123 * unpack simple compression
125 * @param dest destination buffer of dest_len, must be padded with at least 130 bytes
127 static void xan_unpack(unsigned char *dest, const unsigned char *src, int dest_len)
129 unsigned char opcode;
131 unsigned char *dest_end = dest + dest_len;
133 while (dest < dest_end) {
138 if ( (opcode & 0x80) == 0 ) {
142 back = ((opcode & 0x60) << 3) + *src++ + 1;
143 size2 = ((opcode & 0x1c) >> 2) + 3;
145 } else if ( (opcode & 0x40) == 0 ) {
149 back = (bytestream_get_be16(&src) & 0x3fff) + 1;
150 size2 = (opcode & 0x3f) + 4;
156 back = ((opcode & 0x10) << 12) + bytestream_get_be16(&src) + 1;
157 size2 = ((opcode & 0x0c) << 6) + *src++ + 5;
158 if (size + size2 > dest_end - dest)
161 memcpy(dest, src, size); dest += size; src += size;
162 av_memcpy_backptr(dest, back, size2);
165 int finish = opcode >= 0xfc;
166 size = finish ? opcode & 3 : ((opcode & 0x1f) << 2) + 4;
168 memcpy(dest, src, size); dest += size; src += size;
175 static inline void xan_wc3_output_pixel_run(XanContext *s,
176 const unsigned char *pixel_buffer, int x, int y, int pixel_count)
182 int width = s->avctx->width;
183 unsigned char *palette_plane;
185 palette_plane = s->current_frame.data[0];
186 stride = s->current_frame.linesize[0];
187 line_inc = stride - width;
188 index = y * stride + x;
190 while(pixel_count && (index < s->frame_size)) {
191 int count = FFMIN(pixel_count, width - current_x);
192 memcpy(palette_plane + index, pixel_buffer, count);
193 pixel_count -= count;
195 pixel_buffer += count;
198 if (current_x >= width) {
205 static inline void xan_wc3_copy_pixel_run(XanContext *s,
206 int x, int y, int pixel_count, int motion_x, int motion_y)
210 int curframe_index, prevframe_index;
211 int curframe_x, prevframe_x;
212 int width = s->avctx->width;
213 unsigned char *palette_plane, *prev_palette_plane;
215 palette_plane = s->current_frame.data[0];
216 prev_palette_plane = s->last_frame.data[0];
217 stride = s->current_frame.linesize[0];
218 line_inc = stride - width;
219 curframe_index = y * stride + x;
221 prevframe_index = (y + motion_y) * stride + x + motion_x;
222 prevframe_x = x + motion_x;
223 while(pixel_count && (curframe_index < s->frame_size)) {
224 int count = FFMIN3(pixel_count, width - curframe_x, width - prevframe_x);
226 memcpy(palette_plane + curframe_index, prev_palette_plane + prevframe_index, count);
227 pixel_count -= count;
228 curframe_index += count;
229 prevframe_index += count;
231 prevframe_x += count;
233 if (curframe_x >= width) {
234 curframe_index += line_inc;
238 if (prevframe_x >= width) {
239 prevframe_index += line_inc;
245 static void xan_wc3_decode_frame(XanContext *s) {
247 int width = s->avctx->width;
248 int height = s->avctx->height;
249 int total_pixels = width * height;
250 unsigned char opcode;
251 unsigned char flag = 0;
253 int motion_x, motion_y;
256 unsigned char *opcode_buffer = s->buffer1;
257 int opcode_buffer_size = s->buffer1_size;
258 const unsigned char *imagedata_buffer = s->buffer2;
260 /* pointers to segments inside the compressed chunk */
261 const unsigned char *huffman_segment;
262 const unsigned char *size_segment;
263 const unsigned char *vector_segment;
264 const unsigned char *imagedata_segment;
266 huffman_segment = s->buf + AV_RL16(&s->buf[0]);
267 size_segment = s->buf + AV_RL16(&s->buf[2]);
268 vector_segment = s->buf + AV_RL16(&s->buf[4]);
269 imagedata_segment = s->buf + AV_RL16(&s->buf[6]);
271 xan_huffman_decode(opcode_buffer, huffman_segment, opcode_buffer_size);
273 if (imagedata_segment[0] == 2)
274 xan_unpack(s->buffer2, &imagedata_segment[1], s->buffer2_size);
276 imagedata_buffer = &imagedata_segment[1];
278 /* use the decoded data segments to build the frame */
280 while (total_pixels) {
282 opcode = *opcode_buffer++;
309 size += (opcode - 10);
314 size = *size_segment++;
319 size = AV_RB16(&size_segment[0]);
325 size = AV_RB24(size_segment);
333 /* run of (size) pixels is unchanged from last frame */
334 xan_wc3_copy_pixel_run(s, x, y, size, 0, 0);
336 /* output a run of pixels from imagedata_buffer */
337 xan_wc3_output_pixel_run(s, imagedata_buffer, x, y, size);
338 imagedata_buffer += size;
341 /* run-based motion compensation from last frame */
342 motion_x = sign_extend(*vector_segment >> 4, 4);
343 motion_y = sign_extend(*vector_segment & 0xF, 4);
346 /* copy a run of pixels from the previous frame */
347 xan_wc3_copy_pixel_run(s, x, y, size, motion_x, motion_y);
352 /* coordinate accounting */
353 total_pixels -= size;
354 y += (x + size) / width;
355 x = (x + size) % width;
359 static void xan_wc4_decode_frame(XanContext *s) {
362 static const uint8_t gamma_lookup[256] = {
363 0x00, 0x09, 0x10, 0x16, 0x1C, 0x21, 0x27, 0x2C,
364 0x31, 0x35, 0x3A, 0x3F, 0x43, 0x48, 0x4C, 0x50,
365 0x54, 0x59, 0x5D, 0x61, 0x65, 0x69, 0x6D, 0x71,
366 0x75, 0x79, 0x7D, 0x80, 0x84, 0x88, 0x8C, 0x8F,
367 0x93, 0x97, 0x9A, 0x9E, 0xA2, 0xA5, 0xA9, 0xAC,
368 0xB0, 0xB3, 0xB7, 0xBA, 0xBE, 0xC1, 0xC5, 0xC8,
369 0xCB, 0xCF, 0xD2, 0xD5, 0xD9, 0xDC, 0xDF, 0xE3,
370 0xE6, 0xE9, 0xED, 0xF0, 0xF3, 0xF6, 0xFA, 0xFD,
371 0x03, 0x0B, 0x12, 0x18, 0x1D, 0x23, 0x28, 0x2D,
372 0x32, 0x36, 0x3B, 0x40, 0x44, 0x49, 0x4D, 0x51,
373 0x56, 0x5A, 0x5E, 0x62, 0x66, 0x6A, 0x6E, 0x72,
374 0x76, 0x7A, 0x7D, 0x81, 0x85, 0x89, 0x8D, 0x90,
375 0x94, 0x98, 0x9B, 0x9F, 0xA2, 0xA6, 0xAA, 0xAD,
376 0xB1, 0xB4, 0xB8, 0xBB, 0xBF, 0xC2, 0xC5, 0xC9,
377 0xCC, 0xD0, 0xD3, 0xD6, 0xDA, 0xDD, 0xE0, 0xE4,
378 0xE7, 0xEA, 0xED, 0xF1, 0xF4, 0xF7, 0xFA, 0xFD,
379 0x05, 0x0D, 0x13, 0x19, 0x1F, 0x24, 0x29, 0x2E,
380 0x33, 0x38, 0x3C, 0x41, 0x45, 0x4A, 0x4E, 0x52,
381 0x57, 0x5B, 0x5F, 0x63, 0x67, 0x6B, 0x6F, 0x73,
382 0x77, 0x7B, 0x7E, 0x82, 0x86, 0x8A, 0x8D, 0x91,
383 0x95, 0x99, 0x9C, 0xA0, 0xA3, 0xA7, 0xAA, 0xAE,
384 0xB2, 0xB5, 0xB9, 0xBC, 0xBF, 0xC3, 0xC6, 0xCA,
385 0xCD, 0xD0, 0xD4, 0xD7, 0xDA, 0xDE, 0xE1, 0xE4,
386 0xE8, 0xEB, 0xEE, 0xF1, 0xF5, 0xF8, 0xFB, 0xFD,
387 0x07, 0x0E, 0x15, 0x1A, 0x20, 0x25, 0x2A, 0x2F,
388 0x34, 0x39, 0x3D, 0x42, 0x46, 0x4B, 0x4F, 0x53,
389 0x58, 0x5C, 0x60, 0x64, 0x68, 0x6C, 0x70, 0x74,
390 0x78, 0x7C, 0x7F, 0x83, 0x87, 0x8B, 0x8E, 0x92,
391 0x96, 0x99, 0x9D, 0xA1, 0xA4, 0xA8, 0xAB, 0xAF,
392 0xB2, 0xB6, 0xB9, 0xBD, 0xC0, 0xC4, 0xC7, 0xCB,
393 0xCE, 0xD1, 0xD5, 0xD8, 0xDB, 0xDF, 0xE2, 0xE5,
394 0xE9, 0xEC, 0xEF, 0xF2, 0xF6, 0xF9, 0xFC, 0xFD
397 static int xan_decode_frame(AVCodecContext *avctx,
398 void *data, int *data_size,
401 const uint8_t *buf = avpkt->data;
402 int ret, buf_size = avpkt->size;
403 XanContext *s = avctx->priv_data;
405 if (avctx->codec->id == CODEC_ID_XAN_WC3) {
406 const uint8_t *buf_end = buf + buf_size;
408 while (buf_end - buf > 8 && tag != VGA__TAG) {
413 tag = bytestream_get_le32(&buf);
414 size = bytestream_get_be32(&buf);
415 size = FFMIN(size, buf_end - buf);
418 if (size < PALETTE_SIZE)
419 return AVERROR_INVALIDDATA;
420 if (s->palettes_count >= PALETTES_MAX)
421 return AVERROR_INVALIDDATA;
422 tmpptr = av_realloc(s->palettes, (s->palettes_count + 1) * AVPALETTE_SIZE);
424 return AVERROR(ENOMEM);
425 s->palettes = tmpptr;
426 tmpptr += s->palettes_count * AVPALETTE_COUNT;
427 for (i = 0; i < PALETTE_COUNT; i++) {
428 int r = gamma_lookup[*buf++];
429 int g = gamma_lookup[*buf++];
430 int b = gamma_lookup[*buf++];
431 *tmpptr++ = (r << 16) | (g << 8) | b;
437 return AVERROR_INVALIDDATA;
438 new_pal = bytestream_get_le32(&buf);
439 if (new_pal < s->palettes_count) {
440 s->cur_palette = new_pal;
442 av_log(avctx, AV_LOG_ERROR, "Invalid palette selected\n");
451 buf_size = buf_end - buf;
453 if ((ret = avctx->get_buffer(avctx, &s->current_frame))) {
454 av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed\n");
457 s->current_frame.reference = 3;
460 s->frame_size = s->current_frame.linesize[0] * s->avctx->height;
462 if (avctx->codec->id == CODEC_ID_XAN_WC3) {
463 memcpy(s->current_frame.data[1], s->palettes + s->cur_palette * AVPALETTE_COUNT, AVPALETTE_SIZE);
465 AVPaletteControl *palette_control = avctx->palctrl;
466 palette_control->palette_changed = 0;
467 memcpy(s->current_frame.data[1], palette_control->palette,
469 s->current_frame.palette_has_changed = 1;
475 if (avctx->codec->id == CODEC_ID_XAN_WC3)
476 xan_wc3_decode_frame(s);
477 else if (avctx->codec->id == CODEC_ID_XAN_WC4)
478 xan_wc4_decode_frame(s);
480 /* release the last frame if it is allocated */
481 if (s->last_frame.data[0])
482 avctx->release_buffer(avctx, &s->last_frame);
484 *data_size = sizeof(AVFrame);
485 *(AVFrame*)data = s->current_frame;
488 FFSWAP(AVFrame, s->current_frame, s->last_frame);
490 /* always report that the buffer was completely consumed */
494 static av_cold int xan_decode_end(AVCodecContext *avctx)
496 XanContext *s = avctx->priv_data;
498 /* release the frames */
499 if (s->last_frame.data[0])
500 avctx->release_buffer(avctx, &s->last_frame);
501 if (s->current_frame.data[0])
502 avctx->release_buffer(avctx, &s->current_frame);
504 av_freep(&s->buffer1);
505 av_freep(&s->buffer2);
510 AVCodec xan_wc3_decoder = {
520 .long_name = NULL_IF_CONFIG_SMALL("Wing Commander III / Xan"),
524 AVCodec xan_wc4_decoder = {
534 .long_name = NULL_IF_CONFIG_SMALL("Wing Commander IV / Xxan"),