2 * Wing Commander/Xan Video Decoder
3 * Copyright (C) 2003 the ffmpeg project
5 * This file is part of Libav.
7 * Libav 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 * Libav 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 Libav; 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 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, int dest_len,
99 const unsigned char *src, int src_len)
101 unsigned char byte = *src++;
102 unsigned char ival = byte + 0x16;
103 const unsigned char * ptr = src + byte*2;
104 int ptr_len = src_len - 1 - byte*2;
105 unsigned char val = ival;
106 unsigned char *dest_end = dest + dest_len;
110 return AVERROR_INVALIDDATA;
112 init_get_bits(&gb, ptr, ptr_len * 8);
114 while (val != 0x16) {
115 unsigned idx = val - 0x17 + get_bits1(&gb) * byte;
121 if (dest >= dest_end)
132 * unpack simple compression
134 * @param dest destination buffer of dest_len, must be padded with at least 130 bytes
136 static void xan_unpack(unsigned char *dest, int dest_len,
137 const unsigned char *src, int src_len)
139 unsigned char opcode;
141 unsigned char *dest_org = dest;
142 unsigned char *dest_end = dest + dest_len;
143 const unsigned char *src_end = src + src_len;
145 while (dest < dest_end && src < src_end) {
150 if ((opcode & 0x80) == 0) {
153 back = ((opcode & 0x60) << 3) + *src++ + 1;
154 size2 = ((opcode & 0x1c) >> 2) + 3;
155 } else if ((opcode & 0x40) == 0) {
158 back = (bytestream_get_be16(&src) & 0x3fff) + 1;
159 size2 = (opcode & 0x3f) + 4;
163 back = ((opcode & 0x10) << 12) + bytestream_get_be16(&src) + 1;
164 size2 = ((opcode & 0x0c) << 6) + *src++ + 5;
167 if (dest_end - dest < size + size2 ||
168 dest + size - dest_org < back ||
169 src_end - src < size)
171 memcpy(dest, src, size); dest += size; src += size;
172 av_memcpy_backptr(dest, back, size2);
175 int finish = opcode >= 0xfc;
176 size = finish ? opcode & 3 : ((opcode & 0x1f) << 2) + 4;
178 if (dest_end - dest < size || src_end - src < size)
180 memcpy(dest, src, size); dest += size; src += size;
187 static inline void xan_wc3_output_pixel_run(XanContext *s,
188 const unsigned char *pixel_buffer, int x, int y, int pixel_count)
194 int width = s->avctx->width;
195 unsigned char *palette_plane;
197 palette_plane = s->current_frame.data[0];
198 stride = s->current_frame.linesize[0];
199 line_inc = stride - width;
200 index = y * stride + x;
202 while (pixel_count && index < s->frame_size) {
203 int count = FFMIN(pixel_count, width - current_x);
204 memcpy(palette_plane + index, pixel_buffer, count);
205 pixel_count -= count;
207 pixel_buffer += count;
210 if (current_x >= width) {
217 static inline void xan_wc3_copy_pixel_run(XanContext *s, int x, int y,
218 int pixel_count, int motion_x,
223 int curframe_index, prevframe_index;
224 int curframe_x, prevframe_x;
225 int width = s->avctx->width;
226 unsigned char *palette_plane, *prev_palette_plane;
228 if (y + motion_y < 0 || y + motion_y >= s->avctx->height ||
229 x + motion_x < 0 || x + motion_x >= s->avctx->width)
232 palette_plane = s->current_frame.data[0];
233 prev_palette_plane = s->last_frame.data[0];
234 if (!prev_palette_plane)
235 prev_palette_plane = palette_plane;
236 stride = s->current_frame.linesize[0];
237 line_inc = stride - width;
238 curframe_index = y * stride + x;
240 prevframe_index = (y + motion_y) * stride + x + motion_x;
241 prevframe_x = x + motion_x;
242 while (pixel_count &&
243 curframe_index < s->frame_size &&
244 prevframe_index < s->frame_size) {
245 int count = FFMIN3(pixel_count, width - curframe_x,
246 width - prevframe_x);
248 memcpy(palette_plane + curframe_index,
249 prev_palette_plane + prevframe_index, count);
250 pixel_count -= count;
251 curframe_index += count;
252 prevframe_index += count;
254 prevframe_x += count;
256 if (curframe_x >= width) {
257 curframe_index += line_inc;
261 if (prevframe_x >= width) {
262 prevframe_index += line_inc;
268 static int xan_wc3_decode_frame(XanContext *s) {
270 int width = s->avctx->width;
271 int height = s->avctx->height;
272 int total_pixels = width * height;
273 unsigned char opcode;
274 unsigned char flag = 0;
276 int motion_x, motion_y;
279 unsigned char *opcode_buffer = s->buffer1;
280 unsigned char *opcode_buffer_end = s->buffer1 + s->buffer1_size;
281 int opcode_buffer_size = s->buffer1_size;
282 const unsigned char *imagedata_buffer = s->buffer2;
284 /* pointers to segments inside the compressed chunk */
285 const unsigned char *huffman_segment;
286 const unsigned char *size_segment;
287 const unsigned char *vector_segment;
288 const unsigned char *imagedata_segment;
289 int huffman_offset, size_offset, vector_offset, imagedata_offset,
293 return AVERROR_INVALIDDATA;
295 huffman_offset = AV_RL16(&s->buf[0]);
296 size_offset = AV_RL16(&s->buf[2]);
297 vector_offset = AV_RL16(&s->buf[4]);
298 imagedata_offset = AV_RL16(&s->buf[6]);
300 if (huffman_offset >= s->size ||
301 size_offset >= s->size ||
302 vector_offset >= s->size ||
303 imagedata_offset >= s->size)
304 return AVERROR_INVALIDDATA;
306 huffman_segment = s->buf + huffman_offset;
307 size_segment = s->buf + size_offset;
308 vector_segment = s->buf + vector_offset;
309 imagedata_segment = s->buf + imagedata_offset;
311 if (xan_huffman_decode(opcode_buffer, opcode_buffer_size,
312 huffman_segment, s->size - huffman_offset) < 0)
313 return AVERROR_INVALIDDATA;
315 if (imagedata_segment[0] == 2) {
316 xan_unpack(s->buffer2, s->buffer2_size,
317 &imagedata_segment[1], s->size - imagedata_offset - 1);
318 imagedata_size = s->buffer2_size;
320 imagedata_size = s->size - imagedata_offset - 1;
321 imagedata_buffer = &imagedata_segment[1];
324 /* use the decoded data segments to build the frame */
326 while (total_pixels && opcode_buffer < opcode_buffer_end) {
328 opcode = *opcode_buffer++;
355 size += (opcode - 10);
360 size = *size_segment++;
365 size = AV_RB16(&size_segment[0]);
371 size = AV_RB24(size_segment);
376 if (size > total_pixels)
382 /* run of (size) pixels is unchanged from last frame */
383 xan_wc3_copy_pixel_run(s, x, y, size, 0, 0);
385 /* output a run of pixels from imagedata_buffer */
386 if (imagedata_size < size)
388 xan_wc3_output_pixel_run(s, imagedata_buffer, x, y, size);
389 imagedata_buffer += size;
390 imagedata_size -= size;
393 /* run-based motion compensation from last frame */
394 motion_x = sign_extend(*vector_segment >> 4, 4);
395 motion_y = sign_extend(*vector_segment & 0xF, 4);
398 /* copy a run of pixels from the previous frame */
399 xan_wc3_copy_pixel_run(s, x, y, size, motion_x, motion_y);
404 /* coordinate accounting */
405 total_pixels -= size;
406 y += (x + size) / width;
407 x = (x + size) % width;
413 static inline unsigned mul(unsigned a, unsigned b)
415 return (a * b) >> 16;
418 static inline unsigned pow4(unsigned a)
420 unsigned square = mul(a, a);
421 return mul(square, square);
424 static inline unsigned pow5(unsigned a)
426 return mul(pow4(a), a);
429 static uint8_t gamma_corr(uint8_t in) {
430 unsigned lo, hi = 0xff40, target;
432 in = (in << 2) | (in >> 6);
433 /* equivalent float code:
436 return round(pow(in / 256.0, 0.8) * 256);
438 lo = target = in << 8;
440 unsigned mid = (lo + hi) >> 1;
441 unsigned pow = pow5(mid);
442 if (pow > target) hi = mid;
445 return (pow4((lo + hi) >> 1) + 0x80) >> 8;
449 * This is a gamma correction that xan3 applies to all palette entries.
451 * There is a peculiarity, namely that the values are clamped to 253 -
452 * it seems likely that this table was calculated by a buggy fixed-point
453 * implementation, the one above under RUNTIME_GAMMA behaves like this for
455 * The exponent value of 0.8 can be explained by this as well, since 0.8 = 4/5
456 * and thus pow(x, 0.8) is still easy to calculate.
457 * Also, the input values are first rotated to the left by 2.
459 static const uint8_t gamma_lookup[256] = {
460 0x00, 0x09, 0x10, 0x16, 0x1C, 0x21, 0x27, 0x2C,
461 0x31, 0x35, 0x3A, 0x3F, 0x43, 0x48, 0x4C, 0x50,
462 0x54, 0x59, 0x5D, 0x61, 0x65, 0x69, 0x6D, 0x71,
463 0x75, 0x79, 0x7D, 0x80, 0x84, 0x88, 0x8C, 0x8F,
464 0x93, 0x97, 0x9A, 0x9E, 0xA2, 0xA5, 0xA9, 0xAC,
465 0xB0, 0xB3, 0xB7, 0xBA, 0xBE, 0xC1, 0xC5, 0xC8,
466 0xCB, 0xCF, 0xD2, 0xD5, 0xD9, 0xDC, 0xDF, 0xE3,
467 0xE6, 0xE9, 0xED, 0xF0, 0xF3, 0xF6, 0xFA, 0xFD,
468 0x03, 0x0B, 0x12, 0x18, 0x1D, 0x23, 0x28, 0x2D,
469 0x32, 0x36, 0x3B, 0x40, 0x44, 0x49, 0x4D, 0x51,
470 0x56, 0x5A, 0x5E, 0x62, 0x66, 0x6A, 0x6E, 0x72,
471 0x76, 0x7A, 0x7D, 0x81, 0x85, 0x89, 0x8D, 0x90,
472 0x94, 0x98, 0x9B, 0x9F, 0xA2, 0xA6, 0xAA, 0xAD,
473 0xB1, 0xB4, 0xB8, 0xBB, 0xBF, 0xC2, 0xC5, 0xC9,
474 0xCC, 0xD0, 0xD3, 0xD6, 0xDA, 0xDD, 0xE0, 0xE4,
475 0xE7, 0xEA, 0xED, 0xF1, 0xF4, 0xF7, 0xFA, 0xFD,
476 0x05, 0x0D, 0x13, 0x19, 0x1F, 0x24, 0x29, 0x2E,
477 0x33, 0x38, 0x3C, 0x41, 0x45, 0x4A, 0x4E, 0x52,
478 0x57, 0x5B, 0x5F, 0x63, 0x67, 0x6B, 0x6F, 0x73,
479 0x77, 0x7B, 0x7E, 0x82, 0x86, 0x8A, 0x8D, 0x91,
480 0x95, 0x99, 0x9C, 0xA0, 0xA3, 0xA7, 0xAA, 0xAE,
481 0xB2, 0xB5, 0xB9, 0xBC, 0xBF, 0xC3, 0xC6, 0xCA,
482 0xCD, 0xD0, 0xD4, 0xD7, 0xDA, 0xDE, 0xE1, 0xE4,
483 0xE8, 0xEB, 0xEE, 0xF1, 0xF5, 0xF8, 0xFB, 0xFD,
484 0x07, 0x0E, 0x15, 0x1A, 0x20, 0x25, 0x2A, 0x2F,
485 0x34, 0x39, 0x3D, 0x42, 0x46, 0x4B, 0x4F, 0x53,
486 0x58, 0x5C, 0x60, 0x64, 0x68, 0x6C, 0x70, 0x74,
487 0x78, 0x7C, 0x7F, 0x83, 0x87, 0x8B, 0x8E, 0x92,
488 0x96, 0x99, 0x9D, 0xA1, 0xA4, 0xA8, 0xAB, 0xAF,
489 0xB2, 0xB6, 0xB9, 0xBD, 0xC0, 0xC4, 0xC7, 0xCB,
490 0xCE, 0xD1, 0xD5, 0xD8, 0xDB, 0xDF, 0xE2, 0xE5,
491 0xE9, 0xEC, 0xEF, 0xF2, 0xF6, 0xF9, 0xFC, 0xFD
495 static int xan_decode_frame(AVCodecContext *avctx,
496 void *data, int *data_size,
499 const uint8_t *buf = avpkt->data;
500 int ret, buf_size = avpkt->size;
501 XanContext *s = avctx->priv_data;
503 if (avctx->codec->id == CODEC_ID_XAN_WC3) {
504 const uint8_t *buf_end = buf + buf_size;
506 while (buf_end - buf > 8 && tag != VGA__TAG) {
511 tag = bytestream_get_le32(&buf);
512 size = bytestream_get_be32(&buf);
513 size = FFMIN(size, buf_end - buf);
516 if (size < PALETTE_SIZE)
517 return AVERROR_INVALIDDATA;
518 if (s->palettes_count >= PALETTES_MAX)
519 return AVERROR_INVALIDDATA;
520 tmpptr = av_realloc(s->palettes,
521 (s->palettes_count + 1) * AVPALETTE_SIZE);
523 return AVERROR(ENOMEM);
524 s->palettes = tmpptr;
525 tmpptr += s->palettes_count * AVPALETTE_COUNT;
526 for (i = 0; i < PALETTE_COUNT; i++) {
528 int r = gamma_corr(*buf++);
529 int g = gamma_corr(*buf++);
530 int b = gamma_corr(*buf++);
532 int r = gamma_lookup[*buf++];
533 int g = gamma_lookup[*buf++];
534 int b = gamma_lookup[*buf++];
536 *tmpptr++ = (r << 16) | (g << 8) | b;
542 return AVERROR_INVALIDDATA;
543 new_pal = bytestream_get_le32(&buf);
544 if (new_pal < s->palettes_count) {
545 s->cur_palette = new_pal;
547 av_log(avctx, AV_LOG_ERROR, "Invalid palette selected\n");
556 buf_size = buf_end - buf;
558 if (s->palettes_count <= 0) {
559 av_log(s->avctx, AV_LOG_ERROR, "No palette found\n");
560 return AVERROR_INVALIDDATA;
563 if ((ret = avctx->get_buffer(avctx, &s->current_frame))) {
564 av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed\n");
567 s->current_frame.reference = 3;
570 s->frame_size = s->current_frame.linesize[0] * s->avctx->height;
572 memcpy(s->current_frame.data[1],
573 s->palettes + s->cur_palette * AVPALETTE_COUNT, AVPALETTE_SIZE);
578 if (xan_wc3_decode_frame(s) < 0)
579 return AVERROR_INVALIDDATA;
581 /* release the last frame if it is allocated */
582 if (s->last_frame.data[0])
583 avctx->release_buffer(avctx, &s->last_frame);
585 *data_size = sizeof(AVFrame);
586 *(AVFrame*)data = s->current_frame;
589 FFSWAP(AVFrame, s->current_frame, s->last_frame);
591 /* always report that the buffer was completely consumed */
595 static av_cold int xan_decode_end(AVCodecContext *avctx)
597 XanContext *s = avctx->priv_data;
599 /* release the frames */
600 if (s->last_frame.data[0])
601 avctx->release_buffer(avctx, &s->last_frame);
602 if (s->current_frame.data[0])
603 avctx->release_buffer(avctx, &s->current_frame);
605 av_freep(&s->buffer1);
606 av_freep(&s->buffer2);
607 av_freep(&s->palettes);
612 AVCodec ff_xan_wc3_decoder = {
614 .type = AVMEDIA_TYPE_VIDEO,
615 .id = CODEC_ID_XAN_WC3,
616 .priv_data_size = sizeof(XanContext),
617 .init = xan_decode_init,
618 .close = xan_decode_end,
619 .decode = xan_decode_frame,
620 .capabilities = CODEC_CAP_DR1,
621 .long_name = NULL_IF_CONFIG_SMALL("Wing Commander III / Xan"),