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 unsigned idx = val - 0x17 + get_bits1(&gb) * byte;
123 if (dest >= dest_end)
134 * unpack simple compression
136 * @param dest destination buffer of dest_len, must be padded with at least 130 bytes
138 static void xan_unpack(unsigned char *dest, int dest_len,
139 const unsigned char *src, int src_len)
141 unsigned char opcode;
143 unsigned char *dest_org = dest;
144 unsigned char *dest_end = dest + dest_len;
145 const unsigned char *src_end = src + src_len;
147 while (dest < dest_end && src < src_end) {
152 if ( (opcode & 0x80) == 0 ) {
156 back = ((opcode & 0x60) << 3) + *src++ + 1;
157 size2 = ((opcode & 0x1c) >> 2) + 3;
159 } else if ( (opcode & 0x40) == 0 ) {
163 back = (bytestream_get_be16(&src) & 0x3fff) + 1;
164 size2 = (opcode & 0x3f) + 4;
170 back = ((opcode & 0x10) << 12) + bytestream_get_be16(&src) + 1;
171 size2 = ((opcode & 0x0c) << 6) + *src++ + 5;
173 if (dest_end - dest < size + size2 ||
174 dest + size - dest_org < back ||
175 src_end - src < size)
177 memcpy(dest, src, size); dest += size; src += size;
178 av_memcpy_backptr(dest, back, size2);
181 int finish = opcode >= 0xfc;
182 size = finish ? opcode & 3 : ((opcode & 0x1f) << 2) + 4;
184 if (dest_end - dest < size || src_end - src < size)
186 memcpy(dest, src, size); dest += size; src += size;
193 static inline void xan_wc3_output_pixel_run(XanContext *s,
194 const unsigned char *pixel_buffer, int x, int y, int pixel_count)
200 int width = s->avctx->width;
201 unsigned char *palette_plane;
203 palette_plane = s->current_frame.data[0];
204 stride = s->current_frame.linesize[0];
205 line_inc = stride - width;
206 index = y * stride + x;
208 while(pixel_count && (index < s->frame_size)) {
209 int count = FFMIN(pixel_count, width - current_x);
210 memcpy(palette_plane + index, pixel_buffer, count);
211 pixel_count -= count;
213 pixel_buffer += count;
216 if (current_x >= width) {
223 static inline void xan_wc3_copy_pixel_run(XanContext *s,
224 int x, int y, int pixel_count, int motion_x, int motion_y)
228 int curframe_index, prevframe_index;
229 int curframe_x, prevframe_x;
230 int width = s->avctx->width;
231 unsigned char *palette_plane, *prev_palette_plane;
233 if ( y + motion_y < 0 || y + motion_y >= s->avctx->height ||
234 x + motion_x < 0 || x + motion_x >= s->avctx->width)
237 palette_plane = s->current_frame.data[0];
238 prev_palette_plane = s->last_frame.data[0];
239 if (!prev_palette_plane)
240 prev_palette_plane = palette_plane;
241 stride = s->current_frame.linesize[0];
242 line_inc = stride - width;
243 curframe_index = y * stride + x;
245 prevframe_index = (y + motion_y) * stride + x + motion_x;
246 prevframe_x = x + motion_x;
248 curframe_index < s->frame_size &&
249 prevframe_index < s->frame_size) {
250 int count = FFMIN3(pixel_count, width - curframe_x, width - prevframe_x);
252 memcpy(palette_plane + curframe_index, prev_palette_plane + prevframe_index, count);
253 pixel_count -= count;
254 curframe_index += count;
255 prevframe_index += count;
257 prevframe_x += count;
259 if (curframe_x >= width) {
260 curframe_index += line_inc;
264 if (prevframe_x >= width) {
265 prevframe_index += line_inc;
271 static int xan_wc3_decode_frame(XanContext *s) {
273 int width = s->avctx->width;
274 int height = s->avctx->height;
275 int total_pixels = width * height;
276 unsigned char opcode;
277 unsigned char flag = 0;
279 int motion_x, motion_y;
282 unsigned char *opcode_buffer = s->buffer1;
283 unsigned char *opcode_buffer_end = s->buffer1 + s->buffer1_size;
284 int opcode_buffer_size = s->buffer1_size;
285 const unsigned char *imagedata_buffer = s->buffer2;
287 /* pointers to segments inside the compressed chunk */
288 const unsigned char *huffman_segment;
289 const unsigned char *size_segment;
290 const unsigned char *vector_segment;
291 const unsigned char *imagedata_segment;
292 int huffman_offset, size_offset, vector_offset, imagedata_offset, imagedata_size;
295 return AVERROR_INVALIDDATA;
297 huffman_offset = AV_RL16(&s->buf[0]);
298 size_offset = AV_RL16(&s->buf[2]);
299 vector_offset = AV_RL16(&s->buf[4]);
300 imagedata_offset = AV_RL16(&s->buf[6]);
302 if (huffman_offset >= s->size ||
303 size_offset >= s->size ||
304 vector_offset >= s->size ||
305 imagedata_offset >= s->size)
306 return AVERROR_INVALIDDATA;
308 huffman_segment = s->buf + huffman_offset;
309 size_segment = s->buf + size_offset;
310 vector_segment = s->buf + vector_offset;
311 imagedata_segment = s->buf + imagedata_offset;
313 if (xan_huffman_decode(opcode_buffer, opcode_buffer_size,
314 huffman_segment, s->size - huffman_offset) < 0)
315 return AVERROR_INVALIDDATA;
317 if (imagedata_segment[0] == 2) {
318 xan_unpack(s->buffer2, s->buffer2_size,
319 &imagedata_segment[1], s->size - imagedata_offset - 1);
320 imagedata_size = s->buffer2_size;
322 imagedata_size = s->size - imagedata_offset - 1;
323 imagedata_buffer = &imagedata_segment[1];
326 /* use the decoded data segments to build the frame */
328 while (total_pixels && opcode_buffer < opcode_buffer_end) {
330 opcode = *opcode_buffer++;
357 size += (opcode - 10);
362 size = *size_segment++;
367 size = AV_RB16(&size_segment[0]);
373 size = AV_RB24(size_segment);
377 if (size > total_pixels)
383 /* run of (size) pixels is unchanged from last frame */
384 xan_wc3_copy_pixel_run(s, x, y, size, 0, 0);
386 /* output a run of pixels from imagedata_buffer */
387 if (imagedata_size < size)
389 xan_wc3_output_pixel_run(s, imagedata_buffer, x, y, size);
390 imagedata_buffer += size;
391 imagedata_size -= size;
394 /* run-based motion compensation from last frame */
395 motion_x = sign_extend(*vector_segment >> 4, 4);
396 motion_y = sign_extend(*vector_segment & 0xF, 4);
399 /* copy a run of pixels from the previous frame */
400 xan_wc3_copy_pixel_run(s, x, y, size, motion_x, motion_y);
405 /* coordinate accounting */
406 total_pixels -= size;
407 y += (x + size) / width;
408 x = (x + size) % width;
414 static inline unsigned mul(unsigned a, unsigned b)
416 return (a * b) >> 16;
419 static inline unsigned pow4(unsigned a)
421 unsigned square = mul(a, a);
422 return mul(square, square);
425 static inline unsigned pow5(unsigned a)
427 return mul(pow4(a), a);
430 static uint8_t gamma_corr(uint8_t in) {
431 unsigned lo, hi = 0xff40, target;
433 in = (in << 2) | (in >> 6);
434 /* equivalent float code:
437 return round(pow(in / 256.0, 0.8) * 256);
439 lo = target = in << 8;
441 unsigned mid = (lo + hi) >> 1;
442 unsigned pow = pow5(mid);
443 if (pow > target) hi = mid;
446 return (pow4((lo + hi) >> 1) + 0x80) >> 8;
450 * This is a gamma correction that xan3 applies to all palette entries.
452 * There is a peculiarity, namely that the values are clamped to 253 -
453 * it seems likely that this table was calculated by a buggy fixed-point
454 * implementation, the one above under RUNTIME_GAMMA behaves like this for
456 * The exponent value of 0.8 can be explained by this as well, since 0.8 = 4/5
457 * and thus pow(x, 0.8) is still easy to calculate.
458 * Also, the input values are first rotated to the left by 2.
460 static const uint8_t gamma_lookup[256] = {
461 0x00, 0x09, 0x10, 0x16, 0x1C, 0x21, 0x27, 0x2C,
462 0x31, 0x35, 0x3A, 0x3F, 0x43, 0x48, 0x4C, 0x50,
463 0x54, 0x59, 0x5D, 0x61, 0x65, 0x69, 0x6D, 0x71,
464 0x75, 0x79, 0x7D, 0x80, 0x84, 0x88, 0x8C, 0x8F,
465 0x93, 0x97, 0x9A, 0x9E, 0xA2, 0xA5, 0xA9, 0xAC,
466 0xB0, 0xB3, 0xB7, 0xBA, 0xBE, 0xC1, 0xC5, 0xC8,
467 0xCB, 0xCF, 0xD2, 0xD5, 0xD9, 0xDC, 0xDF, 0xE3,
468 0xE6, 0xE9, 0xED, 0xF0, 0xF3, 0xF6, 0xFA, 0xFD,
469 0x03, 0x0B, 0x12, 0x18, 0x1D, 0x23, 0x28, 0x2D,
470 0x32, 0x36, 0x3B, 0x40, 0x44, 0x49, 0x4D, 0x51,
471 0x56, 0x5A, 0x5E, 0x62, 0x66, 0x6A, 0x6E, 0x72,
472 0x76, 0x7A, 0x7D, 0x81, 0x85, 0x89, 0x8D, 0x90,
473 0x94, 0x98, 0x9B, 0x9F, 0xA2, 0xA6, 0xAA, 0xAD,
474 0xB1, 0xB4, 0xB8, 0xBB, 0xBF, 0xC2, 0xC5, 0xC9,
475 0xCC, 0xD0, 0xD3, 0xD6, 0xDA, 0xDD, 0xE0, 0xE4,
476 0xE7, 0xEA, 0xED, 0xF1, 0xF4, 0xF7, 0xFA, 0xFD,
477 0x05, 0x0D, 0x13, 0x19, 0x1F, 0x24, 0x29, 0x2E,
478 0x33, 0x38, 0x3C, 0x41, 0x45, 0x4A, 0x4E, 0x52,
479 0x57, 0x5B, 0x5F, 0x63, 0x67, 0x6B, 0x6F, 0x73,
480 0x77, 0x7B, 0x7E, 0x82, 0x86, 0x8A, 0x8D, 0x91,
481 0x95, 0x99, 0x9C, 0xA0, 0xA3, 0xA7, 0xAA, 0xAE,
482 0xB2, 0xB5, 0xB9, 0xBC, 0xBF, 0xC3, 0xC6, 0xCA,
483 0xCD, 0xD0, 0xD4, 0xD7, 0xDA, 0xDE, 0xE1, 0xE4,
484 0xE8, 0xEB, 0xEE, 0xF1, 0xF5, 0xF8, 0xFB, 0xFD,
485 0x07, 0x0E, 0x15, 0x1A, 0x20, 0x25, 0x2A, 0x2F,
486 0x34, 0x39, 0x3D, 0x42, 0x46, 0x4B, 0x4F, 0x53,
487 0x58, 0x5C, 0x60, 0x64, 0x68, 0x6C, 0x70, 0x74,
488 0x78, 0x7C, 0x7F, 0x83, 0x87, 0x8B, 0x8E, 0x92,
489 0x96, 0x99, 0x9D, 0xA1, 0xA4, 0xA8, 0xAB, 0xAF,
490 0xB2, 0xB6, 0xB9, 0xBD, 0xC0, 0xC4, 0xC7, 0xCB,
491 0xCE, 0xD1, 0xD5, 0xD8, 0xDB, 0xDF, 0xE2, 0xE5,
492 0xE9, 0xEC, 0xEF, 0xF2, 0xF6, 0xF9, 0xFC, 0xFD
496 static int xan_decode_frame(AVCodecContext *avctx,
497 void *data, int *data_size,
500 const uint8_t *buf = avpkt->data;
501 int ret, buf_size = avpkt->size;
502 XanContext *s = avctx->priv_data;
504 if (avctx->codec->id == CODEC_ID_XAN_WC3) {
505 const uint8_t *buf_end = buf + buf_size;
507 while (buf_end - buf > 8 && tag != VGA__TAG) {
512 tag = bytestream_get_le32(&buf);
513 size = bytestream_get_be32(&buf);
514 size = FFMIN(size, buf_end - buf);
517 if (size < PALETTE_SIZE)
518 return AVERROR_INVALIDDATA;
519 if (s->palettes_count >= PALETTES_MAX)
520 return AVERROR_INVALIDDATA;
521 tmpptr = av_realloc(s->palettes, (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], s->palettes + s->cur_palette * AVPALETTE_COUNT, AVPALETTE_SIZE);
577 if (xan_wc3_decode_frame(s) < 0)
578 return AVERROR_INVALIDDATA;
580 /* release the last frame if it is allocated */
581 if (s->last_frame.data[0])
582 avctx->release_buffer(avctx, &s->last_frame);
584 *data_size = sizeof(AVFrame);
585 *(AVFrame*)data = s->current_frame;
588 FFSWAP(AVFrame, s->current_frame, s->last_frame);
590 /* always report that the buffer was completely consumed */
594 static av_cold int xan_decode_end(AVCodecContext *avctx)
596 XanContext *s = avctx->priv_data;
598 /* release the frames */
599 if (s->last_frame.data[0])
600 avctx->release_buffer(avctx, &s->last_frame);
601 if (s->current_frame.data[0])
602 avctx->release_buffer(avctx, &s->current_frame);
604 av_freep(&s->buffer1);
605 av_freep(&s->buffer2);
606 av_freep(&s->palettes);
611 AVCodec ff_xan_wc3_decoder = {
613 .type = AVMEDIA_TYPE_VIDEO,
614 .id = CODEC_ID_XAN_WC3,
615 .priv_data_size = sizeof(XanContext),
616 .init = xan_decode_init,
617 .close = xan_decode_end,
618 .decode = xan_decode_frame,
619 .capabilities = CODEC_CAP_DR1,
620 .long_name = NULL_IF_CONFIG_SMALL("Wing Commander III / Xan"),