xan.c 12.8 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 35
 */

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

36
#include "libavutil/intreadwrite.h"
37 38 39 40 41 42 43 44
#include "avcodec.h"

typedef struct XanContext {

    AVCodecContext *avctx;
    AVFrame last_frame;
    AVFrame current_frame;

Michael Niedermayer's avatar
Michael Niedermayer committed
45
    const unsigned char *buf;
46 47 48 49
    int size;

    /* scratch space */
    unsigned char *buffer1;
50
    int buffer1_size;
51
    unsigned char *buffer2;
52
    int buffer2_size;
53

54
    int frame_size;
55

56
} XanContext;
57

58
static av_cold int xan_decode_init(AVCodecContext *avctx)
59 60 61 62
{
    XanContext *s = avctx->priv_data;

    s->avctx = avctx;
63
    s->frame_size = 0;
64

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

71
    avctx->pix_fmt = PIX_FMT_PAL8;
72

73 74
    if(avcodec_check_dimensions(avctx, avctx->width, avctx->height))
        return -1;
75

76 77 78 79
    s->buffer1_size = avctx->width * avctx->height;
    s->buffer1 = av_malloc(s->buffer1_size);
    s->buffer2_size = avctx->width * avctx->height;
    s->buffer2 = av_malloc(s->buffer2_size);
80 81 82 83 84 85
    if (!s->buffer1 || !s->buffer2)
        return -1;

    return 0;
}

Diego Biurrun's avatar
Diego Biurrun committed
86
/* This function is used in lieu of memcpy(). This decoder cannot use
87 88 89 90
 * memcpy because the memory locations often overlap and
 * memcpy doesn't like that; it's not uncommon, for example, for
 * dest = src+1, to turn byte A into  pattern AAAAAAAA.
 * This was originally repz movsb in Intel x86 ASM. */
Michael Niedermayer's avatar
Michael Niedermayer committed
91
static inline void bytecopy(unsigned char *dest, const unsigned char *src, int count)
92 93 94 95 96 97 98
{
    int i;

    for (i = 0; i < count; i++)
        dest[i] = src[i];
}

Michael Niedermayer's avatar
Michael Niedermayer committed
99
static int xan_huffman_decode(unsigned char *dest, const unsigned char *src,
100
    int dest_len)
101 102 103
{
    unsigned char byte = *src++;
    unsigned char ival = byte + 0x16;
Michael Niedermayer's avatar
Michael Niedermayer committed
104
    const unsigned char * ptr = src + byte*2;
105 106
    unsigned char val = ival;
    int counter = 0;
107
    unsigned char *dest_end = dest + dest_len;
108 109 110 111 112 113 114 115 116 117

    unsigned char bits = *ptr++;

    while ( val != 0x16 ) {
        if ( (1 << counter) & bits )
            val = src[byte + val - 0x17];
        else
            val = src[val - 0x17];

        if ( val < 0x16 ) {
118 119
            if (dest + 1 > dest_end)
                return 0;
120 121 122 123 124 125 126 127 128 129 130 131 132
            *dest++ = val;
            val = ival;
        }

        if (counter++ == 7) {
            counter = 0;
            bits = *ptr++;
        }
    }

    return 0;
}

Michael Niedermayer's avatar
Michael Niedermayer committed
133
static void xan_unpack(unsigned char *dest, const unsigned char *src, int dest_len)
134 135 136 137 138
{
    unsigned char opcode;
    int size;
    int offset;
    int byte1, byte2, byte3;
139
    unsigned char *dest_end = dest + dest_len;
140 141 142 143 144 145 146 147 148

    for (;;) {
        opcode = *src++;

        if ( (opcode & 0x80) == 0 ) {

            offset = *src++;

            size = opcode & 3;
149 150
            if (dest + size > dest_end)
                return;
151 152 153
            bytecopy(dest, src, size);  dest += size;  src += size;

            size = ((opcode & 0x1c) >> 2) + 3;
154 155
            if (dest + size > dest_end)
                return;
156 157 158 159 160 161 162 163 164
            bytecopy (dest, dest - (((opcode & 0x60) << 3) + offset + 1), size);
            dest += size;

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

            byte1 = *src++;
            byte2 = *src++;

            size = byte1 >> 6;
165 166
            if (dest + size > dest_end)
                return;
167 168 169
            bytecopy (dest, src, size);  dest += size;  src += size;

            size = (opcode & 0x3f) + 4;
170 171
            if (dest + size > dest_end)
                return;
172 173 174 175 176 177 178 179 180 181
            bytecopy (dest, dest - (((byte1 & 0x3f) << 8) + byte2 + 1), size);
            dest += size;

        } else if ( (opcode & 0x20) == 0 ) {

            byte1 = *src++;
            byte2 = *src++;
            byte3 = *src++;

            size = opcode & 3;
182 183
            if (dest + size > dest_end)
                return;
184 185 186
            bytecopy (dest, src, size);  dest += size;  src += size;

            size = byte3 + 5 + ((opcode & 0xc) << 6);
187 188
            if (dest + size > dest_end)
                return;
189 190 191 192 193 194 195 196 197 198
            bytecopy (dest,
                dest - ((((opcode & 0x10) >> 4) << 0x10) + 1 + (byte1 << 8) + byte2),
                size);
            dest += size;
        } else {
            size = ((opcode & 0x1f) << 2) + 4;

            if (size > 0x70)
                break;

199 200
            if (dest + size > dest_end)
                return;
201 202 203 204 205 206 207 208
            bytecopy (dest, src, size);  dest += size;  src += size;
        }
    }

    size = opcode & 3;
    bytecopy(dest, src, size);  dest += size;  src += size;
}

209
static inline void xan_wc3_output_pixel_run(XanContext *s,
Aurelien Jacobs's avatar
Aurelien Jacobs committed
210
    const unsigned char *pixel_buffer, int x, int y, int pixel_count)
211 212 213 214 215 216
{
    int stride;
    int line_inc;
    int index;
    int current_x;
    int width = s->avctx->width;
217 218
    unsigned char *palette_plane;

219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
    palette_plane = s->current_frame.data[0];
    stride = s->current_frame.linesize[0];
    line_inc = stride - width;
    index = y * stride + x;
    current_x = x;
    while((pixel_count--) && (index < s->frame_size)) {

        /* don't do a memcpy() here; keyframes generally copy an entire
         * frame of data and the stride needs to be accounted for */
        palette_plane[index++] = *pixel_buffer++;

        current_x++;
        if (current_x >= width) {
            index += line_inc;
            current_x = 0;
234
        }
235 236 237
    }
}

238
static inline void xan_wc3_copy_pixel_run(XanContext *s,
239 240 241 242 243 244 245
    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;
246
    unsigned char *palette_plane, *prev_palette_plane;
247 248 249 250 251 252 253 254 255 256 257

    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;
    while((pixel_count--) && (curframe_index < s->frame_size)) {

258
        palette_plane[curframe_index++] =
259 260 261 262 263 264
            prev_palette_plane[prevframe_index++];

        curframe_x++;
        if (curframe_x >= width) {
            curframe_index += line_inc;
            curframe_x = 0;
265 266
        }

267 268 269 270 271
        prevframe_x++;
        if (prevframe_x >= width) {
            prevframe_index += line_inc;
            prevframe_x = 0;
        }
272 273 274 275 276 277 278 279 280 281 282 283 284 285
    }
}

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;

286
    unsigned char *opcode_buffer = s->buffer1;
287
    int opcode_buffer_size = s->buffer1_size;
Aurelien Jacobs's avatar
Aurelien Jacobs committed
288
    const unsigned char *imagedata_buffer = s->buffer2;
289 290

    /* pointers to segments inside the compressed chunk */
Michael Niedermayer's avatar
Michael Niedermayer committed
291 292 293 294
    const unsigned char *huffman_segment;
    const unsigned char *size_segment;
    const unsigned char *vector_segment;
    const unsigned char *imagedata_segment;
295

296 297 298 299
    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]);
300

301
    xan_huffman_decode(opcode_buffer, huffman_segment, opcode_buffer_size);
302

303
    if (imagedata_segment[0] == 2)
Aurelien Jacobs's avatar
Aurelien Jacobs committed
304
        xan_unpack(s->buffer2, &imagedata_segment[1], s->buffer2_size);
305
    else
306
        imagedata_buffer = &imagedata_segment[1];
307 308 309 310 311

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

312
        opcode = *opcode_buffer++;
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348
        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:
349
            size = AV_RB16(&size_segment[0]);
350 351 352 353 354
            size_segment += 2;
            break;

        case 11:
        case 21:
355
            size = AV_RB24(size_segment);
356 357 358 359 360 361 362 363 364 365
            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 {
366 367 368
                /* output a run of pixels from imagedata_buffer */
                xan_wc3_output_pixel_run(s, imagedata_buffer, x, y, size);
                imagedata_buffer += size;
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407
            }
        } else {
            /* run-based motion compensation from last frame */
            motion_x = (*vector_segment >> 4) & 0xF;
            motion_y = *vector_segment & 0xF;
            vector_segment++;

            /* sign extension */
            if (motion_x & 0x8)
                motion_x |= 0xFFFFFFF0;
            if (motion_y & 0x8)
                motion_y |= 0xFFFFFFF0;

            /* 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;
        while (size) {
            if (x + size >= width) {
                y++;
                size -= (width - x);
                x = 0;
            } else {
                x += size;
                size = 0;
            }
        }
    }
}

static void xan_wc4_decode_frame(XanContext *s) {
}

static int xan_decode_frame(AVCodecContext *avctx,
                            void *data, int *data_size,
Michael Niedermayer's avatar
Michael Niedermayer committed
408
                            const uint8_t *buf, int buf_size)
409 410
{
    XanContext *s = avctx->priv_data;
411
    AVPaletteControl *palette_control = avctx->palctrl;
412 413

    if (avctx->get_buffer(avctx, &s->current_frame)) {
414
        av_log(s->avctx, AV_LOG_ERROR, "  Xan Video: get_buffer() failed\n");
415 416
        return -1;
    }
417
    s->current_frame.reference = 3;
418

419 420 421 422
    if (!s->frame_size)
        s->frame_size = s->current_frame.linesize[0] * s->avctx->height;

    palette_control->palette_changed = 0;
423
    memcpy(s->current_frame.data[1], palette_control->palette,
424 425 426
        AVPALETTE_SIZE);
    s->current_frame.palette_has_changed = 1;

427 428 429
    s->buf = buf;
    s->size = buf_size;

430 431 432
    if (avctx->codec->id == CODEC_ID_XAN_WC3)
        xan_wc3_decode_frame(s);
    else if (avctx->codec->id == CODEC_ID_XAN_WC4)
433
        xan_wc4_decode_frame(s);
434

435 436 437 438 439 440 441
    /* 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;

442 443 444
    /* shuffle frames */
    FFSWAP(AVFrame, s->current_frame, s->last_frame);

445 446 447 448
    /* always report that the buffer was completely consumed */
    return buf_size;
}

449
static av_cold int xan_decode_end(AVCodecContext *avctx)
450 451 452
{
    XanContext *s = avctx->priv_data;

453
    /* release the frames */
454 455
    if (s->last_frame.data[0])
        avctx->release_buffer(avctx, &s->last_frame);
456 457
    if (s->current_frame.data[0])
        avctx->release_buffer(avctx, &s->current_frame);
458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474

    av_free(s->buffer1);
    av_free(s->buffer2);

    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,
475
    .long_name = NULL_IF_CONFIG_SMALL("Wing Commander III / Xan"),
476 477 478 479 480 481 482 483 484 485 486 487 488 489 490
};

/*
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,
};
*/