Statistics
| Branch: | Revision:

ffmpeg / libavcodec / xan.c @ 6a5d31ac

History | View | Annotate | Download (12.8 KB)

1
/*
2
 * Wing Commander/Xan Video Decoder
3
 * Copyright (C) 2003 the ffmpeg project
4
 *
5
 * This file is part of FFmpeg.
6
 *
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.
11
 *
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.
16
 *
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
20
 */
21

    
22
/**
23
 * @file xan.c
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)
27
 *
28
 * The xan_wc3 decoder outputs PAL8 data.
29
 */
30

    
31
#include <stdio.h>
32
#include <stdlib.h>
33
#include <string.h>
34
#include <unistd.h>
35

    
36
#include "libavutil/intreadwrite.h"
37
#include "avcodec.h"
38

    
39
typedef struct XanContext {
40

    
41
    AVCodecContext *avctx;
42
    AVFrame last_frame;
43
    AVFrame current_frame;
44

    
45
    const unsigned char *buf;
46
    int size;
47

    
48
    /* scratch space */
49
    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
    XanContext *s = avctx->priv_data;
61

    
62
    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
        return -1;
69
    }
70

    
71
    avctx->pix_fmt = PIX_FMT_PAL8;
72

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

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

    
83
    return 0;
84
}
85

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

    
95
    for (i = 0; i < count; i++)
96
        dest[i] = src[i];
97
}
98

    
99
static int xan_huffman_decode(unsigned char *dest, const unsigned char *src,
100
    int dest_len)
101
{
102
    unsigned char byte = *src++;
103
    unsigned char ival = byte + 0x16;
104
    const unsigned char * ptr = src + byte*2;
105
    unsigned char val = ival;
106
    int counter = 0;
107
    unsigned char *dest_end = dest + dest_len;
108

    
109
    unsigned char bits = *ptr++;
110

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

    
117
        if ( val < 0x16 ) {
118
            if (dest + 1 > dest_end)
119
                return 0;
120
            *dest++ = val;
121
            val = ival;
122
        }
123

    
124
        if (counter++ == 7) {
125
            counter = 0;
126
            bits = *ptr++;
127
        }
128
    }
129

    
130
    return 0;
131
}
132

    
133
static void xan_unpack(unsigned char *dest, const unsigned char *src, int dest_len)
134
{
135
    unsigned char opcode;
136
    int size;
137
    int offset;
138
    int byte1, byte2, byte3;
139
    unsigned char *dest_end = dest + dest_len;
140

    
141
    for (;;) {
142
        opcode = *src++;
143

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

    
146
            offset = *src++;
147

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

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

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

    
161
            byte1 = *src++;
162
            byte2 = *src++;
163

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

    
169
            size = (opcode & 0x3f) + 4;
170
            if (dest + size > dest_end)
171
                return;
172
            bytecopy (dest, dest - (((byte1 & 0x3f) << 8) + byte2 + 1), size);
173
            dest += size;
174

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

    
177
            byte1 = *src++;
178
            byte2 = *src++;
179
            byte3 = *src++;
180

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

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

    
196
            if (size > 0x70)
197
                break;
198

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

    
205
    size = opcode & 3;
206
    bytecopy(dest, src, size);  dest += size;  src += size;
207
}
208

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

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

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

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

    
238
static inline void xan_wc3_copy_pixel_run(XanContext *s,
239
    int x, int y, int pixel_count, int motion_x, int motion_y)
240
{
241
    int stride;
242
    int line_inc;
243
    int curframe_index, prevframe_index;
244
    int curframe_x, prevframe_x;
245
    int width = s->avctx->width;
246
    unsigned char *palette_plane, *prev_palette_plane;
247

    
248
    palette_plane = s->current_frame.data[0];
249
    prev_palette_plane = s->last_frame.data[0];
250
    stride = s->current_frame.linesize[0];
251
    line_inc = stride - width;
252
    curframe_index = y * stride + x;
253
    curframe_x = x;
254
    prevframe_index = (y + motion_y) * stride + x + motion_x;
255
    prevframe_x = x + motion_x;
256
    while((pixel_count--) && (curframe_index < s->frame_size)) {
257

    
258
        palette_plane[curframe_index++] =
259
            prev_palette_plane[prevframe_index++];
260

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

    
267
        prevframe_x++;
268
        if (prevframe_x >= width) {
269
            prevframe_index += line_inc;
270
            prevframe_x = 0;
271
        }
272
    }
273
}
274

    
275
static void xan_wc3_decode_frame(XanContext *s) {
276

    
277
    int width = s->avctx->width;
278
    int height = s->avctx->height;
279
    int total_pixels = width * height;
280
    unsigned char opcode;
281
    unsigned char flag = 0;
282
    int size = 0;
283
    int motion_x, motion_y;
284
    int x, y;
285

    
286
    unsigned char *opcode_buffer = s->buffer1;
287
    int opcode_buffer_size = s->buffer1_size;
288
    const unsigned char *imagedata_buffer = s->buffer2;
289

    
290
    /* pointers to segments inside the compressed chunk */
291
    const unsigned char *huffman_segment;
292
    const unsigned char *size_segment;
293
    const unsigned char *vector_segment;
294
    const unsigned char *imagedata_segment;
295

    
296
    huffman_segment =   s->buf + AV_RL16(&s->buf[0]);
297
    size_segment =      s->buf + AV_RL16(&s->buf[2]);
298
    vector_segment =    s->buf + AV_RL16(&s->buf[4]);
299
    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)
304
        xan_unpack(s->buffer2, &imagedata_segment[1], s->buffer2_size);
305
    else
306
        imagedata_buffer = &imagedata_segment[1];
307

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

    
312
        opcode = *opcode_buffer++;
313
        size = 0;
314

    
315
        switch (opcode) {
316

    
317
        case 0:
318
            flag ^= 1;
319
            continue;
320

    
321
        case 1:
322
        case 2:
323
        case 3:
324
        case 4:
325
        case 5:
326
        case 6:
327
        case 7:
328
        case 8:
329
            size = opcode;
330
            break;
331

    
332
        case 12:
333
        case 13:
334
        case 14:
335
        case 15:
336
        case 16:
337
        case 17:
338
        case 18:
339
            size += (opcode - 10);
340
            break;
341

    
342
        case 9:
343
        case 19:
344
            size = *size_segment++;
345
            break;
346

    
347
        case 10:
348
        case 20:
349
            size = AV_RB16(&size_segment[0]);
350
            size_segment += 2;
351
            break;
352

    
353
        case 11:
354
        case 21:
355
            size = AV_RB24(size_segment);
356
            size_segment += 3;
357
            break;
358
        }
359

    
360
        if (opcode < 12) {
361
            flag ^= 1;
362
            if (flag) {
363
                /* run of (size) pixels is unchanged from last frame */
364
                xan_wc3_copy_pixel_run(s, x, y, size, 0, 0);
365
            } else {
366
                /* output a run of pixels from imagedata_buffer */
367
                xan_wc3_output_pixel_run(s, imagedata_buffer, x, y, size);
368
                imagedata_buffer += size;
369
            }
370
        } else {
371
            /* run-based motion compensation from last frame */
372
            motion_x = (*vector_segment >> 4) & 0xF;
373
            motion_y = *vector_segment & 0xF;
374
            vector_segment++;
375

    
376
            /* sign extension */
377
            if (motion_x & 0x8)
378
                motion_x |= 0xFFFFFFF0;
379
            if (motion_y & 0x8)
380
                motion_y |= 0xFFFFFFF0;
381

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

    
385
            flag = 0;
386
        }
387

    
388
        /* coordinate accounting */
389
        total_pixels -= size;
390
        while (size) {
391
            if (x + size >= width) {
392
                y++;
393
                size -= (width - x);
394
                x = 0;
395
            } else {
396
                x += size;
397
                size = 0;
398
            }
399
        }
400
    }
401
}
402

    
403
static void xan_wc4_decode_frame(XanContext *s) {
404
}
405

    
406
static int xan_decode_frame(AVCodecContext *avctx,
407
                            void *data, int *data_size,
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
        return -1;
416
    }
417
    s->current_frame.reference = 3;
418

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

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

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

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

    
435
    /* release the last frame if it is allocated */
436
    if (s->last_frame.data[0])
437
        avctx->release_buffer(avctx, &s->last_frame);
438

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

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

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

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

    
453
    /* release the frames */
454
    if (s->last_frame.data[0])
455
        avctx->release_buffer(avctx, &s->last_frame);
456
    if (s->current_frame.data[0])
457
        avctx->release_buffer(avctx, &s->current_frame);
458

    
459
    av_free(s->buffer1);
460
    av_free(s->buffer2);
461

    
462
    return 0;
463
}
464

    
465
AVCodec xan_wc3_decoder = {
466
    "xan_wc3",
467
    CODEC_TYPE_VIDEO,
468
    CODEC_ID_XAN_WC3,
469
    sizeof(XanContext),
470
    xan_decode_init,
471
    NULL,
472
    xan_decode_end,
473
    xan_decode_frame,
474
    CODEC_CAP_DR1,
475
    .long_name = NULL_IF_CONFIG_SMALL("Wing Commander III / Xan"),
476
};
477

    
478
/*
479
AVCodec xan_wc4_decoder = {
480
    "xan_wc4",
481
    CODEC_TYPE_VIDEO,
482
    CODEC_ID_XAN_WC4,
483
    sizeof(XanContext),
484
    xan_decode_init,
485
    NULL,
486
    xan_decode_end,
487
    xan_decode_frame,
488
    CODEC_CAP_DR1,
489
};
490
*/