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 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, 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;
109
init_get_bits(&gb, ptr, ptr_len * 8);
111
while ( val != 0x16 ) {
112
val = src[val - 0x17 + get_bits1(&gb) * byte];
115
if (dest >= dest_end)
126
* unpack simple compression
128
* @param dest destination buffer of dest_len, must be padded with at least 130 bytes
130
static void xan_unpack(unsigned char *dest, const unsigned char *src, int dest_len)
132
unsigned char opcode;
134
unsigned char *dest_end = dest + dest_len;
136
while (dest < dest_end) {
141
if ( (opcode & 0x80) == 0 ) {
145
back = ((opcode & 0x60) << 3) + *src++ + 1;
146
size2 = ((opcode & 0x1c) >> 2) + 3;
148
} else if ( (opcode & 0x40) == 0 ) {
152
back = (bytestream_get_be16(&src) & 0x3fff) + 1;
153
size2 = (opcode & 0x3f) + 4;
159
back = ((opcode & 0x10) << 12) + bytestream_get_be16(&src) + 1;
160
size2 = ((opcode & 0x0c) << 6) + *src++ + 5;
161
if (size + size2 > dest_end - dest)
164
memcpy(dest, src, size); dest += size; src += size;
165
av_memcpy_backptr(dest, back, size2);
168
int finish = opcode >= 0xfc;
169
size = finish ? opcode & 3 : ((opcode & 0x1f) << 2) + 4;
171
memcpy(dest, src, size); dest += size; src += size;
178
static inline void xan_wc3_output_pixel_run(XanContext *s,
179
const unsigned char *pixel_buffer, int x, int y, int pixel_count)
185
int width = s->avctx->width;
186
unsigned char *palette_plane;
188
palette_plane = s->current_frame.data[0];
189
stride = s->current_frame.linesize[0];
190
line_inc = stride - width;
191
index = y * stride + x;
193
while(pixel_count && (index < s->frame_size)) {
194
int count = FFMIN(pixel_count, width - current_x);
195
memcpy(palette_plane + index, pixel_buffer, count);
196
pixel_count -= count;
198
pixel_buffer += count;
201
if (current_x >= width) {
208
static inline void xan_wc3_copy_pixel_run(XanContext *s,
209
int x, int y, int pixel_count, int motion_x, int motion_y)
213
int curframe_index, prevframe_index;
214
int curframe_x, prevframe_x;
215
int width = s->avctx->width;
216
unsigned char *palette_plane, *prev_palette_plane;
218
palette_plane = s->current_frame.data[0];
219
prev_palette_plane = s->last_frame.data[0];
220
stride = s->current_frame.linesize[0];
221
line_inc = stride - width;
222
curframe_index = y * stride + x;
224
prevframe_index = (y + motion_y) * stride + x + motion_x;
225
prevframe_x = x + motion_x;
226
while(pixel_count && (curframe_index < s->frame_size)) {
227
int count = FFMIN3(pixel_count, width - curframe_x, width - prevframe_x);
229
memcpy(palette_plane + curframe_index, prev_palette_plane + prevframe_index, count);
230
pixel_count -= count;
231
curframe_index += count;
232
prevframe_index += count;
234
prevframe_x += count;
236
if (curframe_x >= width) {
237
curframe_index += line_inc;
241
if (prevframe_x >= width) {
242
prevframe_index += line_inc;
248
static void xan_wc3_decode_frame(XanContext *s) {
250
int width = s->avctx->width;
251
int height = s->avctx->height;
252
int total_pixels = width * height;
253
unsigned char opcode;
254
unsigned char flag = 0;
256
int motion_x, motion_y;
259
unsigned char *opcode_buffer = s->buffer1;
260
int opcode_buffer_size = s->buffer1_size;
261
const unsigned char *imagedata_buffer = s->buffer2;
263
/* pointers to segments inside the compressed chunk */
264
const unsigned char *huffman_segment;
265
const unsigned char *size_segment;
266
const unsigned char *vector_segment;
267
const unsigned char *imagedata_segment;
269
huffman_segment = s->buf + AV_RL16(&s->buf[0]);
270
size_segment = s->buf + AV_RL16(&s->buf[2]);
271
vector_segment = s->buf + AV_RL16(&s->buf[4]);
272
imagedata_segment = s->buf + AV_RL16(&s->buf[6]);
274
xan_huffman_decode(opcode_buffer, opcode_buffer_size,
275
huffman_segment, s->size - (huffman_segment - s->buf) );
277
if (imagedata_segment[0] == 2)
278
xan_unpack(s->buffer2, &imagedata_segment[1], s->buffer2_size);
280
imagedata_buffer = &imagedata_segment[1];
282
/* use the decoded data segments to build the frame */
284
while (total_pixels) {
286
opcode = *opcode_buffer++;
313
size += (opcode - 10);
318
size = *size_segment++;
323
size = AV_RB16(&size_segment[0]);
329
size = AV_RB24(size_segment);
337
/* run of (size) pixels is unchanged from last frame */
338
xan_wc3_copy_pixel_run(s, x, y, size, 0, 0);
340
/* output a run of pixels from imagedata_buffer */
341
xan_wc3_output_pixel_run(s, imagedata_buffer, x, y, size);
342
imagedata_buffer += size;
345
/* run-based motion compensation from last frame */
346
motion_x = sign_extend(*vector_segment >> 4, 4);
347
motion_y = sign_extend(*vector_segment & 0xF, 4);
350
/* copy a run of pixels from the previous frame */
351
xan_wc3_copy_pixel_run(s, x, y, size, motion_x, motion_y);
356
/* coordinate accounting */
357
total_pixels -= size;
358
y += (x + size) / width;
359
x = (x + size) % width;
364
static inline unsigned mul(unsigned a, unsigned b)
366
return (a * b) >> 16;
369
static inline unsigned pow4(unsigned a)
371
unsigned square = mul(a, a);
372
return mul(square, square);
375
static inline unsigned pow5(unsigned a)
377
return mul(pow4(a), a);
380
static uint8_t gamma_corr(uint8_t in) {
381
unsigned lo, hi = 0xff40, target;
383
in = (in << 2) | (in >> 6);
384
/* equivalent float code:
387
return round(pow(in / 256.0, 0.8) * 256);
389
lo = target = in << 8;
391
unsigned mid = (lo + hi) >> 1;
392
unsigned pow = pow5(mid);
393
if (pow > target) hi = mid;
396
return (pow4((lo + hi) >> 1) + 0x80) >> 8;
400
* This is a gamma correction that xan3 applies to all palette entries.
402
* There is a peculiarity, namely that the values are clamped to 253 -
403
* it seems likely that this table was calculated by a buggy fixed-point
404
* implementation, the one above under RUNTIME_GAMMA behaves like this for
406
* The exponent value of 0.8 can be explained by this as well, since 0.8 = 4/5
407
* and thus pow(x, 0.8) is still easy to calculate.
408
* Also, the input values are first rotated to the left by 2.
410
static const uint8_t gamma_lookup[256] = {
411
0x00, 0x09, 0x10, 0x16, 0x1C, 0x21, 0x27, 0x2C,
412
0x31, 0x35, 0x3A, 0x3F, 0x43, 0x48, 0x4C, 0x50,
413
0x54, 0x59, 0x5D, 0x61, 0x65, 0x69, 0x6D, 0x71,
414
0x75, 0x79, 0x7D, 0x80, 0x84, 0x88, 0x8C, 0x8F,
415
0x93, 0x97, 0x9A, 0x9E, 0xA2, 0xA5, 0xA9, 0xAC,
416
0xB0, 0xB3, 0xB7, 0xBA, 0xBE, 0xC1, 0xC5, 0xC8,
417
0xCB, 0xCF, 0xD2, 0xD5, 0xD9, 0xDC, 0xDF, 0xE3,
418
0xE6, 0xE9, 0xED, 0xF0, 0xF3, 0xF6, 0xFA, 0xFD,
419
0x03, 0x0B, 0x12, 0x18, 0x1D, 0x23, 0x28, 0x2D,
420
0x32, 0x36, 0x3B, 0x40, 0x44, 0x49, 0x4D, 0x51,
421
0x56, 0x5A, 0x5E, 0x62, 0x66, 0x6A, 0x6E, 0x72,
422
0x76, 0x7A, 0x7D, 0x81, 0x85, 0x89, 0x8D, 0x90,
423
0x94, 0x98, 0x9B, 0x9F, 0xA2, 0xA6, 0xAA, 0xAD,
424
0xB1, 0xB4, 0xB8, 0xBB, 0xBF, 0xC2, 0xC5, 0xC9,
425
0xCC, 0xD0, 0xD3, 0xD6, 0xDA, 0xDD, 0xE0, 0xE4,
426
0xE7, 0xEA, 0xED, 0xF1, 0xF4, 0xF7, 0xFA, 0xFD,
427
0x05, 0x0D, 0x13, 0x19, 0x1F, 0x24, 0x29, 0x2E,
428
0x33, 0x38, 0x3C, 0x41, 0x45, 0x4A, 0x4E, 0x52,
429
0x57, 0x5B, 0x5F, 0x63, 0x67, 0x6B, 0x6F, 0x73,
430
0x77, 0x7B, 0x7E, 0x82, 0x86, 0x8A, 0x8D, 0x91,
431
0x95, 0x99, 0x9C, 0xA0, 0xA3, 0xA7, 0xAA, 0xAE,
432
0xB2, 0xB5, 0xB9, 0xBC, 0xBF, 0xC3, 0xC6, 0xCA,
433
0xCD, 0xD0, 0xD4, 0xD7, 0xDA, 0xDE, 0xE1, 0xE4,
434
0xE8, 0xEB, 0xEE, 0xF1, 0xF5, 0xF8, 0xFB, 0xFD,
435
0x07, 0x0E, 0x15, 0x1A, 0x20, 0x25, 0x2A, 0x2F,
436
0x34, 0x39, 0x3D, 0x42, 0x46, 0x4B, 0x4F, 0x53,
437
0x58, 0x5C, 0x60, 0x64, 0x68, 0x6C, 0x70, 0x74,
438
0x78, 0x7C, 0x7F, 0x83, 0x87, 0x8B, 0x8E, 0x92,
439
0x96, 0x99, 0x9D, 0xA1, 0xA4, 0xA8, 0xAB, 0xAF,
440
0xB2, 0xB6, 0xB9, 0xBD, 0xC0, 0xC4, 0xC7, 0xCB,
441
0xCE, 0xD1, 0xD5, 0xD8, 0xDB, 0xDF, 0xE2, 0xE5,
442
0xE9, 0xEC, 0xEF, 0xF2, 0xF6, 0xF9, 0xFC, 0xFD
446
static int xan_decode_frame(AVCodecContext *avctx,
447
void *data, int *data_size,
450
const uint8_t *buf = avpkt->data;
451
int ret, buf_size = avpkt->size;
452
XanContext *s = avctx->priv_data;
454
if (avctx->codec->id == CODEC_ID_XAN_WC3) {
455
const uint8_t *buf_end = buf + buf_size;
457
while (buf_end - buf > 8 && tag != VGA__TAG) {
462
tag = bytestream_get_le32(&buf);
463
size = bytestream_get_be32(&buf);
464
size = FFMIN(size, buf_end - buf);
467
if (size < PALETTE_SIZE)
468
return AVERROR_INVALIDDATA;
469
if (s->palettes_count >= PALETTES_MAX)
470
return AVERROR_INVALIDDATA;
471
tmpptr = av_realloc(s->palettes, (s->palettes_count + 1) * AVPALETTE_SIZE);
473
return AVERROR(ENOMEM);
474
s->palettes = tmpptr;
475
tmpptr += s->palettes_count * AVPALETTE_COUNT;
476
for (i = 0; i < PALETTE_COUNT; i++) {
478
int r = gamma_corr(*buf++);
479
int g = gamma_corr(*buf++);
480
int b = gamma_corr(*buf++);
482
int r = gamma_lookup[*buf++];
483
int g = gamma_lookup[*buf++];
484
int b = gamma_lookup[*buf++];
486
*tmpptr++ = (r << 16) | (g << 8) | b;
492
return AVERROR_INVALIDDATA;
493
new_pal = bytestream_get_le32(&buf);
494
if (new_pal < s->palettes_count) {
495
s->cur_palette = new_pal;
497
av_log(avctx, AV_LOG_ERROR, "Invalid palette selected\n");
506
buf_size = buf_end - buf;
508
if ((ret = avctx->get_buffer(avctx, &s->current_frame))) {
509
av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed\n");
512
s->current_frame.reference = 3;
515
s->frame_size = s->current_frame.linesize[0] * s->avctx->height;
517
memcpy(s->current_frame.data[1], s->palettes + s->cur_palette * AVPALETTE_COUNT, AVPALETTE_SIZE);
522
xan_wc3_decode_frame(s);
524
/* release the last frame if it is allocated */
525
if (s->last_frame.data[0])
526
avctx->release_buffer(avctx, &s->last_frame);
528
*data_size = sizeof(AVFrame);
529
*(AVFrame*)data = s->current_frame;
532
FFSWAP(AVFrame, s->current_frame, s->last_frame);
534
/* always report that the buffer was completely consumed */
538
static av_cold int xan_decode_end(AVCodecContext *avctx)
540
XanContext *s = avctx->priv_data;
542
/* release the frames */
543
if (s->last_frame.data[0])
544
avctx->release_buffer(avctx, &s->last_frame);
545
if (s->current_frame.data[0])
546
avctx->release_buffer(avctx, &s->current_frame);
548
av_freep(&s->buffer1);
549
av_freep(&s->buffer2);
550
av_freep(&s->palettes);
555
AVCodec ff_xan_wc3_decoder = {
565
.long_name = NULL_IF_CONFIG_SMALL("Wing Commander III / Xan"),