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);
94 avcodec_get_frame_defaults(&s->last_frame);
95 avcodec_get_frame_defaults(&s->current_frame);
100 static int xan_huffman_decode(unsigned char *dest, int dest_len,
101 const unsigned char *src, int src_len)
103 unsigned char byte = *src++;
104 unsigned char ival = byte + 0x16;
105 const unsigned char * ptr = src + byte*2;
106 int ptr_len = src_len - 1 - byte*2;
107 unsigned char val = ival;
108 unsigned char *dest_end = dest + dest_len;
112 return AVERROR_INVALIDDATA;
114 init_get_bits(&gb, ptr, ptr_len * 8);
116 while ( val != 0x16 ) {
117 val = src[val - 0x17 + get_bits1(&gb) * byte];
120 if (dest >= dest_end)
131 * unpack simple compression
133 * @param dest destination buffer of dest_len, must be padded with at least 130 bytes
135 static void xan_unpack(unsigned char *dest, const unsigned char *src, int dest_len)
137 unsigned char opcode;
139 unsigned char *dest_end = dest + dest_len;
141 while (dest < dest_end) {
146 if ( (opcode & 0x80) == 0 ) {
150 back = ((opcode & 0x60) << 3) + *src++ + 1;
151 size2 = ((opcode & 0x1c) >> 2) + 3;
153 } else if ( (opcode & 0x40) == 0 ) {
157 back = (bytestream_get_be16(&src) & 0x3fff) + 1;
158 size2 = (opcode & 0x3f) + 4;
164 back = ((opcode & 0x10) << 12) + bytestream_get_be16(&src) + 1;
165 size2 = ((opcode & 0x0c) << 6) + *src++ + 5;
166 if (size + size2 > dest_end - dest)
169 memcpy(dest, src, size); dest += size; src += size;
170 av_memcpy_backptr(dest, back, size2);
173 int finish = opcode >= 0xfc;
174 size = finish ? opcode & 3 : ((opcode & 0x1f) << 2) + 4;
176 memcpy(dest, src, size); dest += size; src += size;
183 static inline void xan_wc3_output_pixel_run(XanContext *s,
184 const unsigned char *pixel_buffer, int x, int y, int pixel_count)
190 int width = s->avctx->width;
191 unsigned char *palette_plane;
193 palette_plane = s->current_frame.data[0];
194 stride = s->current_frame.linesize[0];
195 line_inc = stride - width;
196 index = y * stride + x;
198 while(pixel_count && (index < s->frame_size)) {
199 int count = FFMIN(pixel_count, width - current_x);
200 memcpy(palette_plane + index, pixel_buffer, count);
201 pixel_count -= count;
203 pixel_buffer += count;
206 if (current_x >= width) {
213 static inline void xan_wc3_copy_pixel_run(XanContext *s,
214 int x, int y, int pixel_count, int motion_x, int motion_y)
218 int curframe_index, prevframe_index;
219 int curframe_x, prevframe_x;
220 int width = s->avctx->width;
221 unsigned char *palette_plane, *prev_palette_plane;
223 if ( y + motion_y < 0 || y + motion_y >= s->avctx->height ||
224 x + motion_x < 0 || x + motion_x >= s->avctx->width)
227 palette_plane = s->current_frame.data[0];
228 prev_palette_plane = s->last_frame.data[0];
229 if (!prev_palette_plane)
230 prev_palette_plane = palette_plane;
231 stride = s->current_frame.linesize[0];
232 line_inc = stride - width;
233 curframe_index = y * stride + x;
235 prevframe_index = (y + motion_y) * stride + x + motion_x;
236 prevframe_x = x + motion_x;
238 curframe_index < s->frame_size &&
239 prevframe_index < s->frame_size) {
240 int count = FFMIN3(pixel_count, width - curframe_x, width - prevframe_x);
242 memcpy(palette_plane + curframe_index, prev_palette_plane + prevframe_index, count);
243 pixel_count -= count;
244 curframe_index += count;
245 prevframe_index += count;
247 prevframe_x += count;
249 if (curframe_x >= width) {
250 curframe_index += line_inc;
254 if (prevframe_x >= width) {
255 prevframe_index += line_inc;
261 static int xan_wc3_decode_frame(XanContext *s) {
263 int width = s->avctx->width;
264 int height = s->avctx->height;
265 int total_pixels = width * height;
266 unsigned char opcode;
267 unsigned char flag = 0;
269 int motion_x, motion_y;
272 unsigned char *opcode_buffer = s->buffer1;
273 unsigned char *opcode_buffer_end = s->buffer1 + s->buffer1_size;
274 int opcode_buffer_size = s->buffer1_size;
275 const unsigned char *imagedata_buffer = s->buffer2;
277 /* pointers to segments inside the compressed chunk */
278 const unsigned char *huffman_segment;
279 const unsigned char *size_segment;
280 const unsigned char *vector_segment;
281 const unsigned char *imagedata_segment;
282 int huffman_offset, size_offset, vector_offset, imagedata_offset, imagedata_size;
285 return AVERROR_INVALIDDATA;
287 huffman_offset = AV_RL16(&s->buf[0]);
288 size_offset = AV_RL16(&s->buf[2]);
289 vector_offset = AV_RL16(&s->buf[4]);
290 imagedata_offset = AV_RL16(&s->buf[6]);
292 if (huffman_offset >= s->size ||
293 size_offset >= s->size ||
294 vector_offset >= s->size ||
295 imagedata_offset >= s->size)
296 return AVERROR_INVALIDDATA;
298 huffman_segment = s->buf + huffman_offset;
299 size_segment = s->buf + size_offset;
300 vector_segment = s->buf + vector_offset;
301 imagedata_segment = s->buf + imagedata_offset;
303 if (xan_huffman_decode(opcode_buffer, opcode_buffer_size,
304 huffman_segment, s->size - huffman_offset) < 0)
305 return AVERROR_INVALIDDATA;
307 if (imagedata_segment[0] == 2) {
308 xan_unpack(s->buffer2, &imagedata_segment[1], s->buffer2_size);
309 imagedata_size = s->buffer2_size;
311 imagedata_size = s->size - imagedata_offset - 1;
312 imagedata_buffer = &imagedata_segment[1];
315 /* use the decoded data segments to build the frame */
317 while (total_pixels && opcode_buffer < opcode_buffer_end) {
319 opcode = *opcode_buffer++;
346 size += (opcode - 10);
351 size = *size_segment++;
356 size = AV_RB16(&size_segment[0]);
362 size = AV_RB24(size_segment);
366 if (size > total_pixels)
372 /* run of (size) pixels is unchanged from last frame */
373 xan_wc3_copy_pixel_run(s, x, y, size, 0, 0);
375 /* output a run of pixels from imagedata_buffer */
376 if (imagedata_size < size)
378 xan_wc3_output_pixel_run(s, imagedata_buffer, x, y, size);
379 imagedata_buffer += size;
380 imagedata_size -= size;
383 /* run-based motion compensation from last frame */
384 motion_x = sign_extend(*vector_segment >> 4, 4);
385 motion_y = sign_extend(*vector_segment & 0xF, 4);
388 /* copy a run of pixels from the previous frame */
389 xan_wc3_copy_pixel_run(s, x, y, size, motion_x, motion_y);
394 /* coordinate accounting */
395 total_pixels -= size;
396 y += (x + size) / width;
397 x = (x + size) % width;
403 static inline unsigned mul(unsigned a, unsigned b)
405 return (a * b) >> 16;
408 static inline unsigned pow4(unsigned a)
410 unsigned square = mul(a, a);
411 return mul(square, square);
414 static inline unsigned pow5(unsigned a)
416 return mul(pow4(a), a);
419 static uint8_t gamma_corr(uint8_t in) {
420 unsigned lo, hi = 0xff40, target;
422 in = (in << 2) | (in >> 6);
423 /* equivalent float code:
426 return round(pow(in / 256.0, 0.8) * 256);
428 lo = target = in << 8;
430 unsigned mid = (lo + hi) >> 1;
431 unsigned pow = pow5(mid);
432 if (pow > target) hi = mid;
435 return (pow4((lo + hi) >> 1) + 0x80) >> 8;
439 * This is a gamma correction that xan3 applies to all palette entries.
441 * There is a peculiarity, namely that the values are clamped to 253 -
442 * it seems likely that this table was calculated by a buggy fixed-point
443 * implementation, the one above under RUNTIME_GAMMA behaves like this for
445 * The exponent value of 0.8 can be explained by this as well, since 0.8 = 4/5
446 * and thus pow(x, 0.8) is still easy to calculate.
447 * Also, the input values are first rotated to the left by 2.
449 static const uint8_t gamma_lookup[256] = {
450 0x00, 0x09, 0x10, 0x16, 0x1C, 0x21, 0x27, 0x2C,
451 0x31, 0x35, 0x3A, 0x3F, 0x43, 0x48, 0x4C, 0x50,
452 0x54, 0x59, 0x5D, 0x61, 0x65, 0x69, 0x6D, 0x71,
453 0x75, 0x79, 0x7D, 0x80, 0x84, 0x88, 0x8C, 0x8F,
454 0x93, 0x97, 0x9A, 0x9E, 0xA2, 0xA5, 0xA9, 0xAC,
455 0xB0, 0xB3, 0xB7, 0xBA, 0xBE, 0xC1, 0xC5, 0xC8,
456 0xCB, 0xCF, 0xD2, 0xD5, 0xD9, 0xDC, 0xDF, 0xE3,
457 0xE6, 0xE9, 0xED, 0xF0, 0xF3, 0xF6, 0xFA, 0xFD,
458 0x03, 0x0B, 0x12, 0x18, 0x1D, 0x23, 0x28, 0x2D,
459 0x32, 0x36, 0x3B, 0x40, 0x44, 0x49, 0x4D, 0x51,
460 0x56, 0x5A, 0x5E, 0x62, 0x66, 0x6A, 0x6E, 0x72,
461 0x76, 0x7A, 0x7D, 0x81, 0x85, 0x89, 0x8D, 0x90,
462 0x94, 0x98, 0x9B, 0x9F, 0xA2, 0xA6, 0xAA, 0xAD,
463 0xB1, 0xB4, 0xB8, 0xBB, 0xBF, 0xC2, 0xC5, 0xC9,
464 0xCC, 0xD0, 0xD3, 0xD6, 0xDA, 0xDD, 0xE0, 0xE4,
465 0xE7, 0xEA, 0xED, 0xF1, 0xF4, 0xF7, 0xFA, 0xFD,
466 0x05, 0x0D, 0x13, 0x19, 0x1F, 0x24, 0x29, 0x2E,
467 0x33, 0x38, 0x3C, 0x41, 0x45, 0x4A, 0x4E, 0x52,
468 0x57, 0x5B, 0x5F, 0x63, 0x67, 0x6B, 0x6F, 0x73,
469 0x77, 0x7B, 0x7E, 0x82, 0x86, 0x8A, 0x8D, 0x91,
470 0x95, 0x99, 0x9C, 0xA0, 0xA3, 0xA7, 0xAA, 0xAE,
471 0xB2, 0xB5, 0xB9, 0xBC, 0xBF, 0xC3, 0xC6, 0xCA,
472 0xCD, 0xD0, 0xD4, 0xD7, 0xDA, 0xDE, 0xE1, 0xE4,
473 0xE8, 0xEB, 0xEE, 0xF1, 0xF5, 0xF8, 0xFB, 0xFD,
474 0x07, 0x0E, 0x15, 0x1A, 0x20, 0x25, 0x2A, 0x2F,
475 0x34, 0x39, 0x3D, 0x42, 0x46, 0x4B, 0x4F, 0x53,
476 0x58, 0x5C, 0x60, 0x64, 0x68, 0x6C, 0x70, 0x74,
477 0x78, 0x7C, 0x7F, 0x83, 0x87, 0x8B, 0x8E, 0x92,
478 0x96, 0x99, 0x9D, 0xA1, 0xA4, 0xA8, 0xAB, 0xAF,
479 0xB2, 0xB6, 0xB9, 0xBD, 0xC0, 0xC4, 0xC7, 0xCB,
480 0xCE, 0xD1, 0xD5, 0xD8, 0xDB, 0xDF, 0xE2, 0xE5,
481 0xE9, 0xEC, 0xEF, 0xF2, 0xF6, 0xF9, 0xFC, 0xFD
485 static int xan_decode_frame(AVCodecContext *avctx,
486 void *data, int *data_size,
489 const uint8_t *buf = avpkt->data;
490 int ret, buf_size = avpkt->size;
491 XanContext *s = avctx->priv_data;
493 if (avctx->codec->id == CODEC_ID_XAN_WC3) {
494 const uint8_t *buf_end = buf + buf_size;
496 while (buf_end - buf > 8 && tag != VGA__TAG) {
501 tag = bytestream_get_le32(&buf);
502 size = bytestream_get_be32(&buf);
503 size = FFMIN(size, buf_end - buf);
506 if (size < PALETTE_SIZE)
507 return AVERROR_INVALIDDATA;
508 if (s->palettes_count >= PALETTES_MAX)
509 return AVERROR_INVALIDDATA;
510 tmpptr = av_realloc(s->palettes, (s->palettes_count + 1) * AVPALETTE_SIZE);
512 return AVERROR(ENOMEM);
513 s->palettes = tmpptr;
514 tmpptr += s->palettes_count * AVPALETTE_COUNT;
515 for (i = 0; i < PALETTE_COUNT; i++) {
517 int r = gamma_corr(*buf++);
518 int g = gamma_corr(*buf++);
519 int b = gamma_corr(*buf++);
521 int r = gamma_lookup[*buf++];
522 int g = gamma_lookup[*buf++];
523 int b = gamma_lookup[*buf++];
525 *tmpptr++ = (r << 16) | (g << 8) | b;
531 return AVERROR_INVALIDDATA;
532 new_pal = bytestream_get_le32(&buf);
533 if (new_pal < s->palettes_count) {
534 s->cur_palette = new_pal;
536 av_log(avctx, AV_LOG_ERROR, "Invalid palette selected\n");
545 buf_size = buf_end - buf;
547 if ((ret = avctx->get_buffer(avctx, &s->current_frame))) {
548 av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed\n");
551 s->current_frame.reference = 3;
554 s->frame_size = s->current_frame.linesize[0] * s->avctx->height;
556 memcpy(s->current_frame.data[1], s->palettes + s->cur_palette * AVPALETTE_COUNT, AVPALETTE_SIZE);
561 if (xan_wc3_decode_frame(s) < 0)
562 return AVERROR_INVALIDDATA;
564 /* release the last frame if it is allocated */
565 if (s->last_frame.data[0])
566 avctx->release_buffer(avctx, &s->last_frame);
568 *data_size = sizeof(AVFrame);
569 *(AVFrame*)data = s->current_frame;
572 FFSWAP(AVFrame, s->current_frame, s->last_frame);
574 /* always report that the buffer was completely consumed */
578 static av_cold int xan_decode_end(AVCodecContext *avctx)
580 XanContext *s = avctx->priv_data;
582 /* release the frames */
583 if (s->last_frame.data[0])
584 avctx->release_buffer(avctx, &s->last_frame);
585 if (s->current_frame.data[0])
586 avctx->release_buffer(avctx, &s->current_frame);
588 av_freep(&s->buffer1);
589 av_freep(&s->buffer2);
590 av_freep(&s->palettes);
595 AVCodec ff_xan_wc3_decoder = {
597 .type = AVMEDIA_TYPE_VIDEO,
598 .id = CODEC_ID_XAN_WC3,
599 .priv_data_size = sizeof(XanContext),
600 .init = xan_decode_init,
601 .close = xan_decode_end,
602 .decode = xan_decode_frame,
603 .capabilities = CODEC_CAP_DR1,
604 .long_name = NULL_IF_CONFIG_SMALL("Wing Commander III / Xan"),