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 libavcodec/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
39typedef 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
58static 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. */
91static 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
99static 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
133static 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
209static 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
238static 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
275static 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
403static void xan_wc4_decode_frame(XanContext *s) {
404}
405
406static 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
449static 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
465AVCodec 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/*
479AVCodec 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*/
491