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 RUNTIME_GAMMA 0
45 #define VGA__TAG MKTAG('V', 'G', 'A', ' ')
46 #define PALT_TAG MKTAG('P', 'A', 'L', 'T')
47 #define SHOT_TAG MKTAG('S', 'H', 'O', 'T')
48 #define PALETTE_COUNT 256
49 #define PALETTE_SIZE (PALETTE_COUNT * 3)
50 #define PALETTES_MAX 256
52 typedef struct XanContext {
54 AVCodecContext *avctx;
56 AVFrame current_frame;
58 const unsigned char *buf;
62 unsigned char *buffer1;
64 unsigned char *buffer2;
75 static av_cold int xan_decode_init(AVCodecContext *avctx)
77 XanContext *s = avctx->priv_data;
82 avctx->pix_fmt = PIX_FMT_PAL8;
84 s->buffer1_size = avctx->width * avctx->height;
85 s->buffer1 = av_malloc(s->buffer1_size);
87 return AVERROR(ENOMEM);
88 s->buffer2_size = avctx->width * avctx->height;
89 s->buffer2 = av_malloc(s->buffer2_size + 130);
91 av_freep(&s->buffer1);
92 return AVERROR(ENOMEM);
98 static int xan_huffman_decode(unsigned char *dest, const unsigned char *src,
101 unsigned char byte = *src++;
102 unsigned char ival = byte + 0x16;
103 const unsigned char * ptr = src + byte*2;
104 unsigned char val = ival;
105 unsigned char *dest_end = dest + dest_len;
108 init_get_bits(&gb, ptr, 0); // FIXME: no src size available
110 while ( val != 0x16 ) {
111 val = src[val - 0x17 + get_bits1(&gb) * byte];
114 if (dest >= dest_end)
125 * unpack simple compression
127 * @param dest destination buffer of dest_len, must be padded with at least 130 bytes
129 static void xan_unpack(unsigned char *dest, const unsigned char *src, int dest_len)
131 unsigned char opcode;
133 unsigned char *dest_end = dest + dest_len;
135 while (dest < dest_end) {
140 if ( (opcode & 0x80) == 0 ) {
144 back = ((opcode & 0x60) << 3) + *src++ + 1;
145 size2 = ((opcode & 0x1c) >> 2) + 3;
147 } else if ( (opcode & 0x40) == 0 ) {
151 back = (bytestream_get_be16(&src) & 0x3fff) + 1;
152 size2 = (opcode & 0x3f) + 4;
158 back = ((opcode & 0x10) << 12) + bytestream_get_be16(&src) + 1;
159 size2 = ((opcode & 0x0c) << 6) + *src++ + 5;
160 if (size + size2 > dest_end - dest)
163 memcpy(dest, src, size); dest += size; src += size;
164 av_memcpy_backptr(dest, back, size2);
167 int finish = opcode >= 0xfc;
168 size = finish ? opcode & 3 : ((opcode & 0x1f) << 2) + 4;
170 memcpy(dest, src, size); dest += size; src += size;
177 static inline void xan_wc3_output_pixel_run(XanContext *s,
178 const unsigned char *pixel_buffer, int x, int y, int pixel_count)
184 int width = s->avctx->width;
185 unsigned char *palette_plane;
187 palette_plane = s->current_frame.data[0];
188 stride = s->current_frame.linesize[0];
189 line_inc = stride - width;
190 index = y * stride + x;
192 while(pixel_count && (index < s->frame_size)) {
193 int count = FFMIN(pixel_count, width - current_x);
194 memcpy(palette_plane + index, pixel_buffer, count);
195 pixel_count -= count;
197 pixel_buffer += count;
200 if (current_x >= width) {
207 static inline void xan_wc3_copy_pixel_run(XanContext *s,
208 int x, int y, int pixel_count, int motion_x, int motion_y)
212 int curframe_index, prevframe_index;
213 int curframe_x, prevframe_x;
214 int width = s->avctx->width;
215 unsigned char *palette_plane, *prev_palette_plane;
217 palette_plane = s->current_frame.data[0];
218 prev_palette_plane = s->last_frame.data[0];
219 stride = s->current_frame.linesize[0];
220 line_inc = stride - width;
221 curframe_index = y * stride + x;
223 prevframe_index = (y + motion_y) * stride + x + motion_x;
224 prevframe_x = x + motion_x;
225 while(pixel_count && (curframe_index < s->frame_size)) {
226 int count = FFMIN3(pixel_count, width - curframe_x, width - prevframe_x);
228 memcpy(palette_plane + curframe_index, prev_palette_plane + prevframe_index, count);
229 pixel_count -= count;
230 curframe_index += count;
231 prevframe_index += count;
233 prevframe_x += count;
235 if (curframe_x >= width) {
236 curframe_index += line_inc;
240 if (prevframe_x >= width) {
241 prevframe_index += line_inc;
247 static void xan_wc3_decode_frame(XanContext *s) {
249 int width = s->avctx->width;
250 int height = s->avctx->height;
251 int total_pixels = width * height;
252 unsigned char opcode;
253 unsigned char flag = 0;
255 int motion_x, motion_y;
258 unsigned char *opcode_buffer = s->buffer1;
259 int opcode_buffer_size = s->buffer1_size;
260 const unsigned char *imagedata_buffer = s->buffer2;
262 /* pointers to segments inside the compressed chunk */
263 const unsigned char *huffman_segment;
264 const unsigned char *size_segment;
265 const unsigned char *vector_segment;
266 const unsigned char *imagedata_segment;
268 huffman_segment = s->buf + AV_RL16(&s->buf[0]);
269 size_segment = s->buf + AV_RL16(&s->buf[2]);
270 vector_segment = s->buf + AV_RL16(&s->buf[4]);
271 imagedata_segment = s->buf + AV_RL16(&s->buf[6]);
273 xan_huffman_decode(opcode_buffer, huffman_segment, opcode_buffer_size);
275 if (imagedata_segment[0] == 2)
276 xan_unpack(s->buffer2, &imagedata_segment[1], s->buffer2_size);
278 imagedata_buffer = &imagedata_segment[1];
280 /* use the decoded data segments to build the frame */
282 while (total_pixels) {
284 opcode = *opcode_buffer++;
311 size += (opcode - 10);
316 size = *size_segment++;
321 size = AV_RB16(&size_segment[0]);
327 size = AV_RB24(size_segment);
335 /* run of (size) pixels is unchanged from last frame */
336 xan_wc3_copy_pixel_run(s, x, y, size, 0, 0);
338 /* output a run of pixels from imagedata_buffer */
339 xan_wc3_output_pixel_run(s, imagedata_buffer, x, y, size);
340 imagedata_buffer += size;
343 /* run-based motion compensation from last frame */
344 motion_x = sign_extend(*vector_segment >> 4, 4);
345 motion_y = sign_extend(*vector_segment & 0xF, 4);
348 /* copy a run of pixels from the previous frame */
349 xan_wc3_copy_pixel_run(s, x, y, size, motion_x, motion_y);
354 /* coordinate accounting */
355 total_pixels -= size;
356 y += (x + size) / width;
357 x = (x + size) % width;
361 static void xan_wc4_decode_frame(XanContext *s) {
365 static inline unsigned mul(unsigned a, unsigned b)
367 return (a * b) >> 16;
370 static inline unsigned pow4(unsigned a)
372 unsigned square = mul(a, a);
373 return mul(square, square);
376 static inline unsigned pow5(unsigned a)
378 return mul(pow4(a), a);
381 static uint8_t gamma_corr(uint8_t in) {
382 unsigned lo, hi = 0xff40, target;
384 in = (in << 2) | (in >> 6);
385 /* equivalent float code:
388 return round(pow(in / 256.0, 0.8) * 256);
390 lo = target = in << 8;
392 unsigned mid = (lo + hi) >> 1;
393 unsigned pow = pow5(mid);
394 if (pow > target) hi = mid;
397 return (pow4((lo + hi) >> 1) + 0x80) >> 8;
401 * This is a gamma correction that xan3 applies to all palette entries.
403 * There is a peculiarity, namely that the values are clamped to 253 -
404 * it seems likely that this table was calculated by a buggy fixed-point
405 * implementation, the one above under RUNTIME_GAMMA behaves like this for
407 * The exponent value of 0.8 can be explained by this as well, since 0.8 = 4/5
408 * and thus pow(x, 0.8) is still easy to calculate.
409 * Also, the input values are first rotated to the left by 2.
411 static const uint8_t gamma_lookup[256] = {
412 0x00, 0x09, 0x10, 0x16, 0x1C, 0x21, 0x27, 0x2C,
413 0x31, 0x35, 0x3A, 0x3F, 0x43, 0x48, 0x4C, 0x50,
414 0x54, 0x59, 0x5D, 0x61, 0x65, 0x69, 0x6D, 0x71,
415 0x75, 0x79, 0x7D, 0x80, 0x84, 0x88, 0x8C, 0x8F,
416 0x93, 0x97, 0x9A, 0x9E, 0xA2, 0xA5, 0xA9, 0xAC,
417 0xB0, 0xB3, 0xB7, 0xBA, 0xBE, 0xC1, 0xC5, 0xC8,
418 0xCB, 0xCF, 0xD2, 0xD5, 0xD9, 0xDC, 0xDF, 0xE3,
419 0xE6, 0xE9, 0xED, 0xF0, 0xF3, 0xF6, 0xFA, 0xFD,
420 0x03, 0x0B, 0x12, 0x18, 0x1D, 0x23, 0x28, 0x2D,
421 0x32, 0x36, 0x3B, 0x40, 0x44, 0x49, 0x4D, 0x51,
422 0x56, 0x5A, 0x5E, 0x62, 0x66, 0x6A, 0x6E, 0x72,
423 0x76, 0x7A, 0x7D, 0x81, 0x85, 0x89, 0x8D, 0x90,
424 0x94, 0x98, 0x9B, 0x9F, 0xA2, 0xA6, 0xAA, 0xAD,
425 0xB1, 0xB4, 0xB8, 0xBB, 0xBF, 0xC2, 0xC5, 0xC9,
426 0xCC, 0xD0, 0xD3, 0xD6, 0xDA, 0xDD, 0xE0, 0xE4,
427 0xE7, 0xEA, 0xED, 0xF1, 0xF4, 0xF7, 0xFA, 0xFD,
428 0x05, 0x0D, 0x13, 0x19, 0x1F, 0x24, 0x29, 0x2E,
429 0x33, 0x38, 0x3C, 0x41, 0x45, 0x4A, 0x4E, 0x52,
430 0x57, 0x5B, 0x5F, 0x63, 0x67, 0x6B, 0x6F, 0x73,
431 0x77, 0x7B, 0x7E, 0x82, 0x86, 0x8A, 0x8D, 0x91,
432 0x95, 0x99, 0x9C, 0xA0, 0xA3, 0xA7, 0xAA, 0xAE,
433 0xB2, 0xB5, 0xB9, 0xBC, 0xBF, 0xC3, 0xC6, 0xCA,
434 0xCD, 0xD0, 0xD4, 0xD7, 0xDA, 0xDE, 0xE1, 0xE4,
435 0xE8, 0xEB, 0xEE, 0xF1, 0xF5, 0xF8, 0xFB, 0xFD,
436 0x07, 0x0E, 0x15, 0x1A, 0x20, 0x25, 0x2A, 0x2F,
437 0x34, 0x39, 0x3D, 0x42, 0x46, 0x4B, 0x4F, 0x53,
438 0x58, 0x5C, 0x60, 0x64, 0x68, 0x6C, 0x70, 0x74,
439 0x78, 0x7C, 0x7F, 0x83, 0x87, 0x8B, 0x8E, 0x92,
440 0x96, 0x99, 0x9D, 0xA1, 0xA4, 0xA8, 0xAB, 0xAF,
441 0xB2, 0xB6, 0xB9, 0xBD, 0xC0, 0xC4, 0xC7, 0xCB,
442 0xCE, 0xD1, 0xD5, 0xD8, 0xDB, 0xDF, 0xE2, 0xE5,
443 0xE9, 0xEC, 0xEF, 0xF2, 0xF6, 0xF9, 0xFC, 0xFD
447 static int xan_decode_frame(AVCodecContext *avctx,
448 void *data, int *data_size,
451 const uint8_t *buf = avpkt->data;
452 int ret, buf_size = avpkt->size;
453 XanContext *s = avctx->priv_data;
455 if (avctx->codec->id == CODEC_ID_XAN_WC3) {
456 const uint8_t *buf_end = buf + buf_size;
458 while (buf_end - buf > 8 && tag != VGA__TAG) {
463 tag = bytestream_get_le32(&buf);
464 size = bytestream_get_be32(&buf);
465 size = FFMIN(size, buf_end - buf);
468 if (size < PALETTE_SIZE)
469 return AVERROR_INVALIDDATA;
470 if (s->palettes_count >= PALETTES_MAX)
471 return AVERROR_INVALIDDATA;
472 tmpptr = av_realloc(s->palettes, (s->palettes_count + 1) * AVPALETTE_SIZE);
474 return AVERROR(ENOMEM);
475 s->palettes = tmpptr;
476 tmpptr += s->palettes_count * AVPALETTE_COUNT;
477 for (i = 0; i < PALETTE_COUNT; i++) {
479 int r = gamma_corr(*buf++);
480 int g = gamma_corr(*buf++);
481 int b = gamma_corr(*buf++);
483 int r = gamma_lookup[*buf++];
484 int g = gamma_lookup[*buf++];
485 int b = gamma_lookup[*buf++];
487 *tmpptr++ = (r << 16) | (g << 8) | b;
493 return AVERROR_INVALIDDATA;
494 new_pal = bytestream_get_le32(&buf);
495 if (new_pal < s->palettes_count) {
496 s->cur_palette = new_pal;
498 av_log(avctx, AV_LOG_ERROR, "Invalid palette selected\n");
507 buf_size = buf_end - buf;
509 if ((ret = avctx->get_buffer(avctx, &s->current_frame))) {
510 av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed\n");
513 s->current_frame.reference = 3;
516 s->frame_size = s->current_frame.linesize[0] * s->avctx->height;
518 if (avctx->codec->id == CODEC_ID_XAN_WC3) {
519 memcpy(s->current_frame.data[1], s->palettes + s->cur_palette * AVPALETTE_COUNT, AVPALETTE_SIZE);
521 AVPaletteControl *palette_control = avctx->palctrl;
522 palette_control->palette_changed = 0;
523 memcpy(s->current_frame.data[1], palette_control->palette,
525 s->current_frame.palette_has_changed = 1;
531 if (avctx->codec->id == CODEC_ID_XAN_WC3)
532 xan_wc3_decode_frame(s);
533 else if (avctx->codec->id == CODEC_ID_XAN_WC4)
534 xan_wc4_decode_frame(s);
536 /* release the last frame if it is allocated */
537 if (s->last_frame.data[0])
538 avctx->release_buffer(avctx, &s->last_frame);
540 *data_size = sizeof(AVFrame);
541 *(AVFrame*)data = s->current_frame;
544 FFSWAP(AVFrame, s->current_frame, s->last_frame);
546 /* always report that the buffer was completely consumed */
550 static av_cold int xan_decode_end(AVCodecContext *avctx)
552 XanContext *s = avctx->priv_data;
554 /* release the frames */
555 if (s->last_frame.data[0])
556 avctx->release_buffer(avctx, &s->last_frame);
557 if (s->current_frame.data[0])
558 avctx->release_buffer(avctx, &s->current_frame);
560 av_freep(&s->buffer1);
561 av_freep(&s->buffer2);
562 av_freep(&s->palettes);
567 AVCodec xan_wc3_decoder = {
577 .long_name = NULL_IF_CONFIG_SMALL("Wing Commander III / Xan"),
581 AVCodec xan_wc4_decoder = {
591 .long_name = NULL_IF_CONFIG_SMALL("Wing Commander IV / Xxan"),