xan.c 11.7 KB
Newer Older
1 2 3 4
/*
 * Wing Commander/Xan Video Decoder
 * Copyright (C) 2003 the ffmpeg project
 *
5 6 7
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
8 9
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
12
 * FFmpeg is distributed in the hope that it will be useful,
13 14 15 16 17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * 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
20 21 22
 */

/**
23
 * @file libavcodec/xan.c
24
 * Xan video decoder for Wing Commander III computer game
25 26
 * by Mario Brito (mbrito@student.dei.uc.pt)
 * and Mike Melanson (melanson@pcisys.net)
27
 *
28
 * The xan_wc3 decoder outputs PAL8 data.
29 30 31 32 33 34
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

35
#include "libavutil/intreadwrite.h"
36
#include "avcodec.h"
37
#include "bytestream.h"
38 39
#define ALT_BITSTREAM_READER_LE
#include "get_bits.h"
40 41
// for av_memcpy_backptr
#include "libavutil/lzo.h"
42 43 44 45 46 47 48

typedef struct XanContext {

    AVCodecContext *avctx;
    AVFrame last_frame;
    AVFrame current_frame;

Michael Niedermayer's avatar
Michael Niedermayer committed
49
    const unsigned char *buf;
50 51 52 53
    int size;

    /* scratch space */
    unsigned char *buffer1;
54
    int buffer1_size;
55
    unsigned char *buffer2;
56
    int buffer2_size;
57

58
    int frame_size;
59

60
} XanContext;
61

62
static av_cold int xan_decode_init(AVCodecContext *avctx)
63 64 65 66
{
    XanContext *s = avctx->priv_data;

    s->avctx = avctx;
67
    s->frame_size = 0;
68

69
    if ((avctx->codec->id == CODEC_ID_XAN_WC3) &&
70
        (s->avctx->palctrl == NULL)) {
71
        av_log(avctx, AV_LOG_ERROR, " WC3 Xan video: palette expected.\n");
72 73 74
        return -1;
    }

75
    avctx->pix_fmt = PIX_FMT_PAL8;
76

77 78
    s->buffer1_size = avctx->width * avctx->height;
    s->buffer1 = av_malloc(s->buffer1_size);
79 80
    if (!s->buffer1)
        return -1;
81
    s->buffer2_size = avctx->width * avctx->height;
82
    s->buffer2 = av_malloc(s->buffer2_size + 130);
83 84
    if (!s->buffer2) {
        av_freep(&s->buffer1);
85
        return -1;
86
    }
87 88 89 90

    return 0;
}

Michael Niedermayer's avatar
Michael Niedermayer committed
91
static int xan_huffman_decode(unsigned char *dest, const unsigned char *src,
92
    int dest_len)
93 94 95
{
    unsigned char byte = *src++;
    unsigned char ival = byte + 0x16;
Michael Niedermayer's avatar
Michael Niedermayer committed
96
    const unsigned char * ptr = src + byte*2;
97
    unsigned char val = ival;
98
    unsigned char *dest_end = dest + dest_len;
99
    GetBitContext gb;
100

101
    init_get_bits(&gb, ptr, 0); // FIXME: no src size available
102 103

    while ( val != 0x16 ) {
104
        val = src[val - 0x17 + get_bits1(&gb) * byte];
105 106

        if ( val < 0x16 ) {
107
            if (dest >= dest_end)
108
                return 0;
109 110 111 112 113 114 115 116
            *dest++ = val;
            val = ival;
        }
    }

    return 0;
}

117 118 119
/**
 * unpack simple compression
 *
120
 * @param dest destination buffer of dest_len, must be padded with at least 130 bytes
121
 */
Michael Niedermayer's avatar
Michael Niedermayer committed
122
static void xan_unpack(unsigned char *dest, const unsigned char *src, int dest_len)
123 124 125
{
    unsigned char opcode;
    int size;
126
    unsigned char *dest_end = dest + dest_len;
127

128
    while (dest < dest_end) {
129 130
        opcode = *src++;

131
        if (opcode < 0xe0) {
132 133
            int size2, back;
            if ( (opcode & 0x80) == 0 ) {
134

135
                size = opcode & 3;
136

137
                back  = ((opcode & 0x60) << 3) + *src++ + 1;
138
                size2 = ((opcode & 0x1c) >> 2) + 3;
139

140
            } else if ( (opcode & 0x40) == 0 ) {
141

142
                size = *src >> 6;
143

144
                back  = (bytestream_get_be16(&src) & 0x3fff) + 1;
145
                size2 = (opcode & 0x3f) + 4;
146

147
            } else {
148

149
                size = opcode & 3;
150

151 152
                back  = ((opcode & 0x10) << 12) + bytestream_get_be16(&src) + 1;
                size2 = ((opcode & 0x0c) <<  6) + *src++ + 5;
153
                if (size + size2 > dest_end - dest)
154
                    return;
155 156 157 158
            }
            memcpy(dest, src, size);  dest += size;  src += size;
            av_memcpy_backptr(dest, back, size2);
            dest += size2;
159
        } else {
160 161
            int finish = opcode >= 0xfc;
            size = finish ? opcode & 3 : ((opcode & 0x1f) << 2) + 4;
162

163
            memcpy(dest, src, size);  dest += size;  src += size;
164 165
            if (finish)
                return;
166 167 168 169
        }
    }
}

170
static inline void xan_wc3_output_pixel_run(XanContext *s,
Aurelien Jacobs's avatar
Aurelien Jacobs committed
171
    const unsigned char *pixel_buffer, int x, int y, int pixel_count)
172 173 174 175 176 177
{
    int stride;
    int line_inc;
    int index;
    int current_x;
    int width = s->avctx->width;
178 179
    unsigned char *palette_plane;

180 181 182 183 184
    palette_plane = s->current_frame.data[0];
    stride = s->current_frame.linesize[0];
    line_inc = stride - width;
    index = y * stride + x;
    current_x = x;
185 186 187 188 189 190 191
    while(pixel_count && (index < s->frame_size)) {
        int count = FFMIN(pixel_count, width - current_x);
        memcpy(palette_plane + index, pixel_buffer, count);
        pixel_count  -= count;
        index        += count;
        pixel_buffer += count;
        current_x    += count;
192 193 194 195

        if (current_x >= width) {
            index += line_inc;
            current_x = 0;
196
        }
197 198 199
    }
}

200
static inline void xan_wc3_copy_pixel_run(XanContext *s,
201 202 203 204 205 206 207
    int x, int y, int pixel_count, int motion_x, int motion_y)
{
    int stride;
    int line_inc;
    int curframe_index, prevframe_index;
    int curframe_x, prevframe_x;
    int width = s->avctx->width;
208
    unsigned char *palette_plane, *prev_palette_plane;
209 210 211 212 213 214 215 216 217

    palette_plane = s->current_frame.data[0];
    prev_palette_plane = s->last_frame.data[0];
    stride = s->current_frame.linesize[0];
    line_inc = stride - width;
    curframe_index = y * stride + x;
    curframe_x = x;
    prevframe_index = (y + motion_y) * stride + x + motion_x;
    prevframe_x = x + motion_x;
218 219
    while(pixel_count && (curframe_index < s->frame_size)) {
        int count = FFMIN3(pixel_count, width - curframe_x, width - prevframe_x);
220

221 222 223 224 225 226
        memcpy(palette_plane + curframe_index, prev_palette_plane + prevframe_index, count);
        pixel_count     -= count;
        curframe_index  += count;
        prevframe_index += count;
        curframe_x      += count;
        prevframe_x     += count;
227 228 229 230

        if (curframe_x >= width) {
            curframe_index += line_inc;
            curframe_x = 0;
231 232
        }

233 234 235 236
        if (prevframe_x >= width) {
            prevframe_index += line_inc;
            prevframe_x = 0;
        }
237 238 239 240 241 242 243 244 245 246 247 248 249 250
    }
}

static void xan_wc3_decode_frame(XanContext *s) {

    int width = s->avctx->width;
    int height = s->avctx->height;
    int total_pixels = width * height;
    unsigned char opcode;
    unsigned char flag = 0;
    int size = 0;
    int motion_x, motion_y;
    int x, y;

251
    unsigned char *opcode_buffer = s->buffer1;
252
    int opcode_buffer_size = s->buffer1_size;
Aurelien Jacobs's avatar
Aurelien Jacobs committed
253
    const unsigned char *imagedata_buffer = s->buffer2;
254 255

    /* pointers to segments inside the compressed chunk */
Michael Niedermayer's avatar
Michael Niedermayer committed
256 257 258 259
    const unsigned char *huffman_segment;
    const unsigned char *size_segment;
    const unsigned char *vector_segment;
    const unsigned char *imagedata_segment;
260

261 262 263 264
    huffman_segment =   s->buf + AV_RL16(&s->buf[0]);
    size_segment =      s->buf + AV_RL16(&s->buf[2]);
    vector_segment =    s->buf + AV_RL16(&s->buf[4]);
    imagedata_segment = s->buf + AV_RL16(&s->buf[6]);
265

266
    xan_huffman_decode(opcode_buffer, huffman_segment, opcode_buffer_size);
267

268
    if (imagedata_segment[0] == 2)
Aurelien Jacobs's avatar
Aurelien Jacobs committed
269
        xan_unpack(s->buffer2, &imagedata_segment[1], s->buffer2_size);
270
    else
271
        imagedata_buffer = &imagedata_segment[1];
272 273 274 275 276

    /* use the decoded data segments to build the frame */
    x = y = 0;
    while (total_pixels) {

277
        opcode = *opcode_buffer++;
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
        size = 0;

        switch (opcode) {

        case 0:
            flag ^= 1;
            continue;

        case 1:
        case 2:
        case 3:
        case 4:
        case 5:
        case 6:
        case 7:
        case 8:
            size = opcode;
            break;

        case 12:
        case 13:
        case 14:
        case 15:
        case 16:
        case 17:
        case 18:
            size += (opcode - 10);
            break;

        case 9:
        case 19:
            size = *size_segment++;
            break;

        case 10:
        case 20:
314
            size = AV_RB16(&size_segment[0]);
315 316 317 318 319
            size_segment += 2;
            break;

        case 11:
        case 21:
320
            size = AV_RB24(size_segment);
321 322 323 324 325 326 327 328 329 330
            size_segment += 3;
            break;
        }

        if (opcode < 12) {
            flag ^= 1;
            if (flag) {
                /* run of (size) pixels is unchanged from last frame */
                xan_wc3_copy_pixel_run(s, x, y, size, 0, 0);
            } else {
331 332 333
                /* output a run of pixels from imagedata_buffer */
                xan_wc3_output_pixel_run(s, imagedata_buffer, x, y, size);
                imagedata_buffer += size;
334 335 336
            }
        } else {
            /* run-based motion compensation from last frame */
337 338
            motion_x = sign_extend(*vector_segment >> 4,  4);
            motion_y = sign_extend(*vector_segment & 0xF, 4);
339 340 341 342 343 344 345 346 347 348
            vector_segment++;

            /* copy a run of pixels from the previous frame */
            xan_wc3_copy_pixel_run(s, x, y, size, motion_x, motion_y);

            flag = 0;
        }

        /* coordinate accounting */
        total_pixels -= size;
349 350
        y += (x + size) / width;
        x  = (x + size) % width;
351 352 353 354 355 356 357 358
    }
}

static void xan_wc4_decode_frame(XanContext *s) {
}

static int xan_decode_frame(AVCodecContext *avctx,
                            void *data, int *data_size,
359
                            AVPacket *avpkt)
360
{
361 362
    const uint8_t *buf = avpkt->data;
    int buf_size = avpkt->size;
363
    XanContext *s = avctx->priv_data;
364
    AVPaletteControl *palette_control = avctx->palctrl;
365 366

    if (avctx->get_buffer(avctx, &s->current_frame)) {
367
        av_log(s->avctx, AV_LOG_ERROR, "  Xan Video: get_buffer() failed\n");
368 369
        return -1;
    }
370
    s->current_frame.reference = 3;
371

372 373 374 375
    if (!s->frame_size)
        s->frame_size = s->current_frame.linesize[0] * s->avctx->height;

    palette_control->palette_changed = 0;
376
    memcpy(s->current_frame.data[1], palette_control->palette,
377
           AVPALETTE_SIZE);
378 379
    s->current_frame.palette_has_changed = 1;

380 381 382
    s->buf = buf;
    s->size = buf_size;

383 384 385
    if (avctx->codec->id == CODEC_ID_XAN_WC3)
        xan_wc3_decode_frame(s);
    else if (avctx->codec->id == CODEC_ID_XAN_WC4)
386
        xan_wc4_decode_frame(s);
387

388 389 390 391 392 393 394
    /* release the last frame if it is allocated */
    if (s->last_frame.data[0])
        avctx->release_buffer(avctx, &s->last_frame);

    *data_size = sizeof(AVFrame);
    *(AVFrame*)data = s->current_frame;

395 396 397
    /* shuffle frames */
    FFSWAP(AVFrame, s->current_frame, s->last_frame);

398 399 400 401
    /* always report that the buffer was completely consumed */
    return buf_size;
}

402
static av_cold int xan_decode_end(AVCodecContext *avctx)
403 404 405
{
    XanContext *s = avctx->priv_data;

406
    /* release the frames */
407 408
    if (s->last_frame.data[0])
        avctx->release_buffer(avctx, &s->last_frame);
409 410
    if (s->current_frame.data[0])
        avctx->release_buffer(avctx, &s->current_frame);
411

412 413
    av_freep(&s->buffer1);
    av_freep(&s->buffer2);
414 415 416 417 418 419 420 421 422 423 424 425 426 427

    return 0;
}

AVCodec xan_wc3_decoder = {
    "xan_wc3",
    CODEC_TYPE_VIDEO,
    CODEC_ID_XAN_WC3,
    sizeof(XanContext),
    xan_decode_init,
    NULL,
    xan_decode_end,
    xan_decode_frame,
    CODEC_CAP_DR1,
428
    .long_name = NULL_IF_CONFIG_SMALL("Wing Commander III / Xan"),
429 430 431 432 433 434 435 436 437 438 439 440 441
};

/*
AVCodec xan_wc4_decoder = {
    "xan_wc4",
    CODEC_TYPE_VIDEO,
    CODEC_ID_XAN_WC4,
    sizeof(XanContext),
    xan_decode_init,
    NULL,
    xan_decode_end,
    xan_decode_frame,
    CODEC_CAP_DR1,
442
    .long_name = NULL_IF_CONFIG_SMALL("Wing Commander IV / Xxan"),
443 444
};
*/