Statistics
| Branch: | Revision:

ffmpeg / libavcodec / xan.c @ 5509bffa

History | View | Annotate | Download (12.6 KB)

1
/*
2
 * Wing Commander/Xan Video Decoder
3
 * Copyright (C) 2003 the ffmpeg project
4
 *
5
 * This library is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU Lesser General Public
7
 * License as published by the Free Software Foundation; either
8
 * version 2 of the License, or (at your option) any later version.
9
 *
10
 * This library is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 * Lesser General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Lesser General Public
16
 * License along with this library; if not, write to the Free Software
17
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
 *
19
 */
20

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

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

    
35
#include "common.h"
36
#include "avcodec.h"
37

    
38
typedef struct XanContext {
39

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

    
44
    unsigned char *buf;
45
    int size;
46

    
47
    /* scratch space */
48
    unsigned char *buffer1;
49
    int buffer1_size;
50
    unsigned char *buffer2;
51
    int buffer2_size;
52

    
53
    int frame_size;
54

    
55
} XanContext;
56

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

    
61
    s->avctx = avctx;
62
    s->frame_size = 0;
63

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

    
70
    avctx->pix_fmt = PIX_FMT_PAL8;
71
    avctx->has_b_frames = 0;
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 can not 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, 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, unsigned char *src,
100
    int dest_len)
101
{
102
    unsigned char byte = *src++;
103
    unsigned char ival = byte + 0x16;
104
    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, 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 void inline xan_wc3_output_pixel_run(XanContext *s,
210
    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 void inline 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
    unsigned char *imagedata_buffer = s->buffer2;
289
    int imagedata_buffer_size = s->buffer2_size;
290

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

    
297
    huffman_segment =   s->buf + LE_16(&s->buf[0]);
298
    size_segment =      s->buf + LE_16(&s->buf[2]);
299
    vector_segment =    s->buf + LE_16(&s->buf[4]);
300
    imagedata_segment = s->buf + LE_16(&s->buf[6]);
301

    
302
    xan_huffman_decode(opcode_buffer, huffman_segment, opcode_buffer_size);
303

    
304
    if (imagedata_segment[0] == 2)
305
        xan_unpack(imagedata_buffer, &imagedata_segment[1],
306
            imagedata_buffer_size);
307
    else
308
        imagedata_buffer = &imagedata_segment[1];
309

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

    
314
        opcode = *opcode_buffer++;
315
        size = 0;
316

    
317
        switch (opcode) {
318

    
319
        case 0:
320
            flag ^= 1;
321
            continue;
322

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

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

    
344
        case 9:
345
        case 19:
346
            size = *size_segment++;
347
            break;
348

    
349
        case 10:
350
        case 20:
351
            size = BE_16(&size_segment[0]);
352
            size_segment += 2;
353
            break;
354

    
355
        case 11:
356
        case 21:
357
            size = (size_segment[0] << 16) | (size_segment[1] << 8) |
358
                size_segment[2];
359
            size_segment += 3;
360
            break;
361
        }
362

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

    
379
            /* sign extension */
380
            if (motion_x & 0x8)
381
                motion_x |= 0xFFFFFFF0;
382
            if (motion_y & 0x8)
383
                motion_y |= 0xFFFFFFF0;
384

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

    
388
            flag = 0;
389
        }
390

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

    
406
static void xan_wc4_decode_frame(XanContext *s) {
407
}
408

    
409
static int xan_decode_frame(AVCodecContext *avctx,
410
                            void *data, int *data_size,
411
                            uint8_t *buf, int buf_size)
412
{
413
    XanContext *s = avctx->priv_data;
414
    AVPaletteControl *palette_control = avctx->palctrl;
415

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

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

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

    
430
    s->buf = buf;
431
    s->size = buf_size;
432

    
433
    if (avctx->codec->id == CODEC_ID_XAN_WC3)
434
        xan_wc3_decode_frame(s);
435
    else if (avctx->codec->id == CODEC_ID_XAN_WC4)
436
        xan_wc4_decode_frame(s);
437

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

    
442
    /* shuffle frames */
443
    s->last_frame = s->current_frame;
444

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

    
448
    /* always report that the buffer was completely consumed */
449
    return buf_size;
450
}
451

    
452
static int xan_decode_end(AVCodecContext *avctx)
453
{
454
    XanContext *s = avctx->priv_data;
455

    
456
    /* release the last frame */
457
    if (s->last_frame.data[0])
458
        avctx->release_buffer(avctx, &s->last_frame);
459

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

    
463
    return 0;
464
}
465

    
466
AVCodec xan_wc3_decoder = {
467
    "xan_wc3",
468
    CODEC_TYPE_VIDEO,
469
    CODEC_ID_XAN_WC3,
470
    sizeof(XanContext),
471
    xan_decode_init,
472
    NULL,
473
    xan_decode_end,
474
    xan_decode_frame,
475
    CODEC_CAP_DR1,
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
*/