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
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
35#include "libavutil/intreadwrite.h"
36#include "avcodec.h"
37#include "bytestream.h"
38#define ALT_BITSTREAM_READER_LE
39#include "get_bits.h"
40// for av_memcpy_backptr
41#include "libavutil/lzo.h"
42
43typedef struct XanContext {
44
45    AVCodecContext *avctx;
46    AVFrame last_frame;
47    AVFrame current_frame;
48
49    const unsigned char *buf;
50    int size;
51
52    /* scratch space */
53    unsigned char *buffer1;
54    int buffer1_size;
55    unsigned char *buffer2;
56    int buffer2_size;
57
58    int frame_size;
59
60} XanContext;
61
62static av_cold int xan_decode_init(AVCodecContext *avctx)
63{
64    XanContext *s = avctx->priv_data;
65
66    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        return -1;
73    }
74
75    avctx->pix_fmt = PIX_FMT_PAL8;
76
77    s->buffer1_size = avctx->width * avctx->height;
78    s->buffer1 = av_malloc(s->buffer1_size);
79    if (!s->buffer1)
80        return -1;
81    s->buffer2_size = avctx->width * avctx->height;
82    s->buffer2 = av_malloc(s->buffer2_size + 130);
83    if (!s->buffer2) {
84        av_freep(&s->buffer1);
85        return -1;
86    }
87
88    return 0;
89}
90
91static int xan_huffman_decode(unsigned char *dest, const unsigned char *src,
92    int dest_len)
93{
94    unsigned char byte = *src++;
95    unsigned char ival = byte + 0x16;
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            *dest++ = val;
110            val = ival;
111        }
112    }
113
114    return 0;
115}
116
117/**
118 * unpack simple compression
119 *
120 * @param dest destination buffer of dest_len, must be padded with at least 130 bytes
121 */
122static void xan_unpack(unsigned char *dest, const unsigned char *src, int dest_len)
123{
124    unsigned char opcode;
125    int size;
126    unsigned char *dest_end = dest + dest_len;
127
128    while (dest < dest_end) {
129        opcode = *src++;
130
131        if (opcode < 0xe0) {
132            int size2, back;
133            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                back  = ((opcode & 0x10) << 12) + bytestream_get_be16(&src) + 1;
152                size2 = ((opcode & 0x0c) <<  6) + *src++ + 5;
153                if (size + size2 > dest_end - dest)
154                    return;
155            }
156            memcpy(dest, src, size);  dest += size;  src += size;
157            av_memcpy_backptr(dest, back, size2);
158            dest += size2;
159        } else {
160            int finish = opcode >= 0xfc;
161            size = finish ? opcode & 3 : ((opcode & 0x1f) << 2) + 4;
162
163            memcpy(dest, src, size);  dest += size;  src += size;
164            if (finish)
165                return;
166        }
167    }
168}
169
170static inline void xan_wc3_output_pixel_run(XanContext *s,
171    const unsigned char *pixel_buffer, int x, int y, int pixel_count)
172{
173    int stride;
174    int line_inc;
175    int index;
176    int current_x;
177    int width = s->avctx->width;
178    unsigned char *palette_plane;
179
180    palette_plane = s->current_frame.data[0];
181    stride = s->current_frame.linesize[0];
182    line_inc = stride - width;
183    index = y * stride + x;
184    current_x = x;
185    while(pixel_count && (index < s->frame_size)) {
186        int count = FFMIN(pixel_count, width - current_x);
187        memcpy(palette_plane + index, pixel_buffer, count);
188        pixel_count  -= count;
189        index        += count;
190        pixel_buffer += count;
191        current_x    += count;
192
193        if (current_x >= width) {
194            index += line_inc;
195            current_x = 0;
196        }
197    }
198}
199
200static inline void xan_wc3_copy_pixel_run(XanContext *s,
201    int x, int y, int pixel_count, int motion_x, int motion_y)
202{
203    int stride;
204    int line_inc;
205    int curframe_index, prevframe_index;
206    int curframe_x, prevframe_x;
207    int width = s->avctx->width;
208    unsigned char *palette_plane, *prev_palette_plane;
209
210    palette_plane = s->current_frame.data[0];
211    prev_palette_plane = s->last_frame.data[0];
212    stride = s->current_frame.linesize[0];
213    line_inc = stride - width;
214    curframe_index = y * stride + x;
215    curframe_x = x;
216    prevframe_index = (y + motion_y) * stride + x + motion_x;
217    prevframe_x = x + motion_x;
218    while(pixel_count && (curframe_index < s->frame_size)) {
219        int count = FFMIN3(pixel_count, width - curframe_x, width - prevframe_x);
220
221        memcpy(palette_plane + curframe_index, prev_palette_plane + prevframe_index, count);
222        pixel_count     -= count;
223        curframe_index  += count;
224        prevframe_index += count;
225        curframe_x      += count;
226        prevframe_x     += count;
227
228        if (curframe_x >= width) {
229            curframe_index += line_inc;
230            curframe_x = 0;
231        }
232
233        if (prevframe_x >= width) {
234            prevframe_index += line_inc;
235            prevframe_x = 0;
236        }
237    }
238}
239
240static void xan_wc3_decode_frame(XanContext *s) {
241
242    int width = s->avctx->width;
243    int height = s->avctx->height;
244    int total_pixels = width * height;
245    unsigned char opcode;
246    unsigned char flag = 0;
247    int size = 0;
248    int motion_x, motion_y;
249    int x, y;
250
251    unsigned char *opcode_buffer = s->buffer1;
252    int opcode_buffer_size = s->buffer1_size;
253    const unsigned char *imagedata_buffer = s->buffer2;
254
255    /* pointers to segments inside the compressed chunk */
256    const unsigned char *huffman_segment;
257    const unsigned char *size_segment;
258    const unsigned char *vector_segment;
259    const unsigned char *imagedata_segment;
260
261    huffman_segment =   s->buf + AV_RL16(&s->buf[0]);
262    size_segment =      s->buf + AV_RL16(&s->buf[2]);
263    vector_segment =    s->buf + AV_RL16(&s->buf[4]);
264    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)
269        xan_unpack(s->buffer2, &imagedata_segment[1], s->buffer2_size);
270    else
271        imagedata_buffer = &imagedata_segment[1];
272
273    /* use the decoded data segments to build the frame */
274    x = y = 0;
275    while (total_pixels) {
276
277        opcode = *opcode_buffer++;
278        size = 0;
279
280        switch (opcode) {
281
282        case 0:
283            flag ^= 1;
284            continue;
285
286        case 1:
287        case 2:
288        case 3:
289        case 4:
290        case 5:
291        case 6:
292        case 7:
293        case 8:
294            size = opcode;
295            break;
296
297        case 12:
298        case 13:
299        case 14:
300        case 15:
301        case 16:
302        case 17:
303        case 18:
304            size += (opcode - 10);
305            break;
306
307        case 9:
308        case 19:
309            size = *size_segment++;
310            break;
311
312        case 10:
313        case 20:
314            size = AV_RB16(&size_segment[0]);
315            size_segment += 2;
316            break;
317
318        case 11:
319        case 21:
320            size = AV_RB24(size_segment);
321            size_segment += 3;
322            break;
323        }
324
325        if (opcode < 12) {
326            flag ^= 1;
327            if (flag) {
328                /* run of (size) pixels is unchanged from last frame */
329                xan_wc3_copy_pixel_run(s, x, y, size, 0, 0);
330            } else {
331                /* output a run of pixels from imagedata_buffer */
332                xan_wc3_output_pixel_run(s, imagedata_buffer, x, y, size);
333                imagedata_buffer += size;
334            }
335        } else {
336            /* run-based motion compensation from last frame */
337            motion_x = sign_extend(*vector_segment >> 4,  4);
338            motion_y = sign_extend(*vector_segment & 0xF, 4);
339            vector_segment++;
340
341            /* copy a run of pixels from the previous frame */
342            xan_wc3_copy_pixel_run(s, x, y, size, motion_x, motion_y);
343
344            flag = 0;
345        }
346
347        /* coordinate accounting */
348        total_pixels -= size;
349        y += (x + size) / width;
350        x  = (x + size) % width;
351    }
352}
353
354static void xan_wc4_decode_frame(XanContext *s) {
355}
356
357static int xan_decode_frame(AVCodecContext *avctx,
358                            void *data, int *data_size,
359                            AVPacket *avpkt)
360{
361    const uint8_t *buf = avpkt->data;
362    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        return -1;
369    }
370    s->current_frame.reference = 3;
371
372    if (!s->frame_size)
373        s->frame_size = s->current_frame.linesize[0] * s->avctx->height;
374
375    palette_control->palette_changed = 0;
376    memcpy(s->current_frame.data[1], palette_control->palette,
377           AVPALETTE_SIZE);
378    s->current_frame.palette_has_changed = 1;
379
380    s->buf = buf;
381    s->size = buf_size;
382
383    if (avctx->codec->id == CODEC_ID_XAN_WC3)
384        xan_wc3_decode_frame(s);
385    else if (avctx->codec->id == CODEC_ID_XAN_WC4)
386        xan_wc4_decode_frame(s);
387
388    /* release the last frame if it is allocated */
389    if (s->last_frame.data[0])
390        avctx->release_buffer(avctx, &s->last_frame);
391
392    *data_size = sizeof(AVFrame);
393    *(AVFrame*)data = s->current_frame;
394
395    /* shuffle frames */
396    FFSWAP(AVFrame, s->current_frame, s->last_frame);
397
398    /* always report that the buffer was completely consumed */
399    return buf_size;
400}
401
402static av_cold int xan_decode_end(AVCodecContext *avctx)
403{
404    XanContext *s = avctx->priv_data;
405
406    /* release the frames */
407    if (s->last_frame.data[0])
408        avctx->release_buffer(avctx, &s->last_frame);
409    if (s->current_frame.data[0])
410        avctx->release_buffer(avctx, &s->current_frame);
411
412    av_freep(&s->buffer1);
413    av_freep(&s->buffer2);
414
415    return 0;
416}
417
418AVCodec xan_wc3_decoder = {
419    "xan_wc3",
420    AVMEDIA_TYPE_VIDEO,
421    CODEC_ID_XAN_WC3,
422    sizeof(XanContext),
423    xan_decode_init,
424    NULL,
425    xan_decode_end,
426    xan_decode_frame,
427    CODEC_CAP_DR1,
428    .long_name = NULL_IF_CONFIG_SMALL("Wing Commander III / Xan"),
429};
430
431/*
432AVCodec xan_wc4_decoder = {
433    "xan_wc4",
434    AVMEDIA_TYPE_VIDEO,
435    CODEC_ID_XAN_WC4,
436    sizeof(XanContext),
437    xan_decode_init,
438    NULL,
439    xan_decode_end,
440    xan_decode_frame,
441    CODEC_CAP_DR1,
442    .long_name = NULL_IF_CONFIG_SMALL("Wing Commander IV / Xxan"),
443};
444*/
445