1c2e97cda239e967b1925fe6b6e6e4cf9668916b
[ffmpeg.git] / libavcodec / xan.c
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 "libavutil/mem.h"
37 #include "avcodec.h"
38 #include "bytestream.h"
39 #define BITSTREAM_READER_LE
40 #include "get_bits.h"
41 #include "internal.h"
42
43 #define RUNTIME_GAMMA 0
44
45 #define VGA__TAG MKTAG('V', 'G', 'A', ' ')
46 #define PALT_TAG MKTAG('P', 'A', 'L', 'T')
47 #define SHOT_TAG MKTAG('S', 'H', 'O', 'T')
48 #define PALETTE_COUNT 256
49 #define PALETTE_SIZE (PALETTE_COUNT * 3)
50 #define PALETTES_MAX 256
51
52 typedef struct XanContext {
53
54     AVCodecContext *avctx;
55     AVFrame *last_frame;
56
57     const uint8_t *buf;
58     int size;
59
60     /* scratch space */
61     uint8_t *buffer1;
62     int buffer1_size;
63     uint8_t *buffer2;
64     int buffer2_size;
65
66     unsigned *palettes;
67     int palettes_count;
68     int cur_palette;
69
70     int frame_size;
71
72 } XanContext;
73
74 static av_cold int xan_decode_end(AVCodecContext *avctx);
75
76 static av_cold int xan_decode_init(AVCodecContext *avctx)
77 {
78     XanContext *s = avctx->priv_data;
79
80     s->avctx = avctx;
81     s->frame_size = 0;
82
83     avctx->pix_fmt = AV_PIX_FMT_PAL8;
84
85     s->buffer1_size = avctx->width * avctx->height;
86     s->buffer1 = av_malloc(s->buffer1_size);
87     if (!s->buffer1)
88         return AVERROR(ENOMEM);
89     s->buffer2_size = avctx->width * avctx->height;
90     s->buffer2 = av_malloc(s->buffer2_size + 130);
91     if (!s->buffer2) {
92         av_freep(&s->buffer1);
93         return AVERROR(ENOMEM);
94     }
95     s->last_frame = av_frame_alloc();
96     if (!s->last_frame) {
97         xan_decode_end(avctx);
98         return AVERROR(ENOMEM);
99     }
100
101     return 0;
102 }
103
104 static int xan_huffman_decode(uint8_t *dest, int dest_len,
105                               const uint8_t *src, int src_len)
106 {
107     uint8_t byte = *src++;
108     uint8_t ival = byte + 0x16;
109     const uint8_t * ptr = src + byte*2;
110     int ptr_len = src_len - 1 - byte*2;
111     uint8_t val = ival;
112     uint8_t *dest_end = dest + dest_len;
113     uint8_t *dest_start = dest;
114     GetBitContext gb;
115
116     if (ptr_len < 0)
117         return AVERROR_INVALIDDATA;
118
119     init_get_bits(&gb, ptr, ptr_len * 8);
120
121     while (val != 0x16) {
122         unsigned idx = val - 0x17 + get_bits1(&gb) * byte;
123         if (idx >= 2 * byte)
124             return AVERROR_INVALIDDATA;
125         val = src[idx];
126
127         if (val < 0x16) {
128             if (dest >= dest_end)
129                 return dest_len;
130             *dest++ = val;
131             val = ival;
132         }
133     }
134
135     return dest - dest_start;
136 }
137
138 /**
139  * unpack simple compression
140  *
141  * @param dest destination buffer of dest_len, must be padded with at least 130 bytes
142  */
143 static void xan_unpack(uint8_t *dest, int dest_len,
144                        const uint8_t *src, int src_len)
145 {
146     uint8_t opcode;
147     int size;
148     uint8_t *dest_org = dest;
149     uint8_t *dest_end = dest + dest_len;
150     GetByteContext ctx;
151
152     bytestream2_init(&ctx, src, src_len);
153     while (dest < dest_end && bytestream2_get_bytes_left(&ctx)) {
154         opcode = bytestream2_get_byte(&ctx);
155
156         if (opcode < 0xe0) {
157             int size2, back;
158             if ((opcode & 0x80) == 0) {
159                 size = opcode & 3;
160
161                 back  = ((opcode & 0x60) << 3) + bytestream2_get_byte(&ctx) + 1;
162                 size2 = ((opcode & 0x1c) >> 2) + 3;
163             } else if ((opcode & 0x40) == 0) {
164                 size = bytestream2_peek_byte(&ctx) >> 6;
165
166                 back  = (bytestream2_get_be16(&ctx) & 0x3fff) + 1;
167                 size2 = (opcode & 0x3f) + 4;
168             } else {
169                 size = opcode & 3;
170
171                 back  = ((opcode & 0x10) << 12) + bytestream2_get_be16(&ctx) + 1;
172                 size2 = ((opcode & 0x0c) <<  6) + bytestream2_get_byte(&ctx) + 5;
173             }
174
175             if (dest_end - dest < size + size2 ||
176                 dest + size - dest_org < back ||
177                 bytestream2_get_bytes_left(&ctx) < size)
178                 return;
179             bytestream2_get_buffer(&ctx, dest, size);
180             dest += size;
181             av_memcpy_backptr(dest, back, size2);
182             dest += size2;
183         } else {
184             int finish = opcode >= 0xfc;
185             size = finish ? opcode & 3 : ((opcode & 0x1f) << 2) + 4;
186
187             if (dest_end - dest < size || bytestream2_get_bytes_left(&ctx) < size)
188                 return;
189             bytestream2_get_buffer(&ctx, dest, size);
190             dest += size;
191             if (finish)
192                 return;
193         }
194     }
195 }
196
197 static inline void xan_wc3_output_pixel_run(XanContext *s, AVFrame *frame,
198     const uint8_t *pixel_buffer, int x, int y, int pixel_count)
199 {
200     int stride;
201     int line_inc;
202     int index;
203     int current_x;
204     int width = s->avctx->width;
205     uint8_t *palette_plane;
206
207     palette_plane = frame->data[0];
208     stride = frame->linesize[0];
209     line_inc = stride - width;
210     index = y * stride + x;
211     current_x = x;
212     while (pixel_count && index < s->frame_size) {
213         int count = FFMIN(pixel_count, width - current_x);
214         memcpy(palette_plane + index, pixel_buffer, count);
215         pixel_count  -= count;
216         index        += count;
217         pixel_buffer += count;
218         current_x    += count;
219
220         if (current_x >= width) {
221             index += line_inc;
222             current_x = 0;
223         }
224     }
225 }
226
227 static inline void xan_wc3_copy_pixel_run(XanContext *s, AVFrame *frame,
228                                           int x, int y,
229                                           int pixel_count, int motion_x,
230                                           int motion_y)
231 {
232     int stride;
233     int line_inc;
234     int curframe_index, prevframe_index;
235     int curframe_x, prevframe_x;
236     int width = s->avctx->width;
237     uint8_t *palette_plane, *prev_palette_plane;
238
239     if (y + motion_y < 0 || y + motion_y >= s->avctx->height ||
240         x + motion_x < 0 || x + motion_x >= s->avctx->width)
241         return;
242
243     palette_plane = frame->data[0];
244     prev_palette_plane = s->last_frame->data[0];
245     if (!prev_palette_plane)
246         prev_palette_plane = palette_plane;
247     stride = frame->linesize[0];
248     line_inc = stride - width;
249     curframe_index = y * stride + x;
250     curframe_x = x;
251     prevframe_index = (y + motion_y) * stride + x + motion_x;
252     prevframe_x = x + motion_x;
253
254     if (prev_palette_plane == palette_plane && FFABS(curframe_index - prevframe_index) < pixel_count) {
255          avpriv_request_sample(s->avctx, "Overlapping copy\n");
256          return ;
257     }
258
259     while (pixel_count &&
260            curframe_index  < s->frame_size &&
261            prevframe_index < s->frame_size) {
262         int count = FFMIN3(pixel_count, width - curframe_x,
263                            width - prevframe_x);
264
265         memcpy(palette_plane + curframe_index,
266                prev_palette_plane + prevframe_index, count);
267         pixel_count     -= count;
268         curframe_index  += count;
269         prevframe_index += count;
270         curframe_x      += count;
271         prevframe_x     += count;
272
273         if (curframe_x >= width) {
274             curframe_index += line_inc;
275             curframe_x = 0;
276         }
277
278         if (prevframe_x >= width) {
279             prevframe_index += line_inc;
280             prevframe_x = 0;
281         }
282     }
283 }
284
285 static int xan_wc3_decode_frame(XanContext *s, AVFrame *frame)
286 {
287
288     int width  = s->avctx->width;
289     int height = s->avctx->height;
290     int total_pixels = width * height;
291     uint8_t opcode;
292     uint8_t flag = 0;
293     int size = 0;
294     int motion_x, motion_y;
295     int x, y, ret;
296
297     uint8_t *opcode_buffer = s->buffer1;
298     uint8_t *opcode_buffer_end = s->buffer1 + s->buffer1_size;
299     int opcode_buffer_size = s->buffer1_size;
300     const uint8_t *imagedata_buffer = s->buffer2;
301
302     /* pointers to segments inside the compressed chunk */
303     const uint8_t *huffman_segment;
304     GetByteContext       size_segment;
305     GetByteContext       vector_segment;
306     const uint8_t *imagedata_segment;
307     int huffman_offset, size_offset, vector_offset, imagedata_offset,
308         imagedata_size;
309
310     if (s->size < 8)
311         return AVERROR_INVALIDDATA;
312
313     huffman_offset    = AV_RL16(&s->buf[0]);
314     size_offset       = AV_RL16(&s->buf[2]);
315     vector_offset     = AV_RL16(&s->buf[4]);
316     imagedata_offset  = AV_RL16(&s->buf[6]);
317
318     if (huffman_offset   >= s->size ||
319         size_offset      >= s->size ||
320         vector_offset    >= s->size ||
321         imagedata_offset >= s->size)
322         return AVERROR_INVALIDDATA;
323
324     huffman_segment   = s->buf + huffman_offset;
325     bytestream2_init(&size_segment,   s->buf + size_offset,   s->size - size_offset);
326     bytestream2_init(&vector_segment, s->buf + vector_offset, s->size - vector_offset);
327     imagedata_segment = s->buf + imagedata_offset;
328
329     if ((ret = xan_huffman_decode(opcode_buffer, opcode_buffer_size,
330                                   huffman_segment, s->size - huffman_offset)) < 0)
331         return AVERROR_INVALIDDATA;
332     opcode_buffer_end = opcode_buffer + ret;
333
334     if (imagedata_segment[0] == 2) {
335         xan_unpack(s->buffer2, s->buffer2_size,
336                    &imagedata_segment[1], s->size - imagedata_offset - 1);
337         imagedata_size = s->buffer2_size;
338     } else {
339         imagedata_size = s->size - imagedata_offset - 1;
340         imagedata_buffer = &imagedata_segment[1];
341     }
342
343     /* use the decoded data segments to build the frame */
344     x = y = 0;
345     while (total_pixels && opcode_buffer < opcode_buffer_end) {
346
347         opcode = *opcode_buffer++;
348         size = 0;
349
350         switch (opcode) {
351
352         case 0:
353             flag ^= 1;
354             continue;
355
356         case 1:
357         case 2:
358         case 3:
359         case 4:
360         case 5:
361         case 6:
362         case 7:
363         case 8:
364             size = opcode;
365             break;
366
367         case 12:
368         case 13:
369         case 14:
370         case 15:
371         case 16:
372         case 17:
373         case 18:
374             size += (opcode - 10);
375             break;
376
377         case 9:
378         case 19:
379             if (bytestream2_get_bytes_left(&size_segment) < 1) {
380                 av_log(s->avctx, AV_LOG_ERROR, "size_segment overread\n");
381                 return AVERROR_INVALIDDATA;
382             }
383             size = bytestream2_get_byte(&size_segment);
384             break;
385
386         case 10:
387         case 20:
388             if (bytestream2_get_bytes_left(&size_segment) < 2) {
389                 av_log(s->avctx, AV_LOG_ERROR, "size_segment overread\n");
390                 return AVERROR_INVALIDDATA;
391             }
392             size = bytestream2_get_be16(&size_segment);
393             break;
394
395         case 11:
396         case 21:
397             if (bytestream2_get_bytes_left(&size_segment) < 3) {
398                 av_log(s->avctx, AV_LOG_ERROR, "size_segment overread\n");
399                 return AVERROR_INVALIDDATA;
400             }
401             size = bytestream2_get_be24(&size_segment);
402             break;
403         }
404
405         if (size > total_pixels)
406             break;
407
408         if (opcode < 12) {
409             flag ^= 1;
410             if (flag) {
411                 /* run of (size) pixels is unchanged from last frame */
412                 xan_wc3_copy_pixel_run(s, frame, x, y, size, 0, 0);
413             } else {
414                 /* output a run of pixels from imagedata_buffer */
415                 if (imagedata_size < size)
416                     break;
417                 xan_wc3_output_pixel_run(s, frame, imagedata_buffer, x, y, size);
418                 imagedata_buffer += size;
419                 imagedata_size -= size;
420             }
421         } else {
422             uint8_t vector;
423             if (bytestream2_get_bytes_left(&vector_segment) <= 0) {
424                 av_log(s->avctx, AV_LOG_ERROR, "vector_segment overread\n");
425                 return AVERROR_INVALIDDATA;
426             }
427             /* run-based motion compensation from last frame */
428             vector = bytestream2_get_byte(&vector_segment);
429             motion_x = sign_extend(vector >> 4,  4);
430             motion_y = sign_extend(vector & 0xF, 4);
431
432             /* copy a run of pixels from the previous frame */
433             xan_wc3_copy_pixel_run(s, frame, x, y, size, motion_x, motion_y);
434
435             flag = 0;
436         }
437
438         /* coordinate accounting */
439         total_pixels -= size;
440         y += (x + size) / width;
441         x  = (x + size) % width;
442     }
443     return 0;
444 }
445
446 #if RUNTIME_GAMMA
447 static inline unsigned mul(unsigned a, unsigned b)
448 {
449     return (a * b) >> 16;
450 }
451
452 static inline unsigned pow4(unsigned a)
453 {
454     unsigned square = mul(a, a);
455     return mul(square, square);
456 }
457
458 static inline unsigned pow5(unsigned a)
459 {
460     return mul(pow4(a), a);
461 }
462
463 static uint8_t gamma_corr(uint8_t in) {
464     unsigned lo, hi = 0xff40, target;
465     int i = 15;
466     in = (in << 2) | (in >> 6);
467     /*  equivalent float code:
468     if (in >= 252)
469         return 253;
470     return round(pow(in / 256.0, 0.8) * 256);
471     */
472     lo = target = in << 8;
473     do {
474         unsigned mid = (lo + hi) >> 1;
475         unsigned pow = pow5(mid);
476         if (pow > target) hi = mid;
477         else lo = mid;
478     } while (--i);
479     return (pow4((lo + hi) >> 1) + 0x80) >> 8;
480 }
481 #else
482 /**
483  * This is a gamma correction that xan3 applies to all palette entries.
484  *
485  * There is a peculiarity, namely that the values are clamped to 253 -
486  * it seems likely that this table was calculated by a buggy fixed-point
487  * implementation, the one above under RUNTIME_GAMMA behaves like this for
488  * example.
489  * The exponent value of 0.8 can be explained by this as well, since 0.8 = 4/5
490  * and thus pow(x, 0.8) is still easy to calculate.
491  * Also, the input values are first rotated to the left by 2.
492  */
493 static const uint8_t gamma_lookup[256] = {
494     0x00, 0x09, 0x10, 0x16, 0x1C, 0x21, 0x27, 0x2C,
495     0x31, 0x35, 0x3A, 0x3F, 0x43, 0x48, 0x4C, 0x50,
496     0x54, 0x59, 0x5D, 0x61, 0x65, 0x69, 0x6D, 0x71,
497     0x75, 0x79, 0x7D, 0x80, 0x84, 0x88, 0x8C, 0x8F,
498     0x93, 0x97, 0x9A, 0x9E, 0xA2, 0xA5, 0xA9, 0xAC,
499     0xB0, 0xB3, 0xB7, 0xBA, 0xBE, 0xC1, 0xC5, 0xC8,
500     0xCB, 0xCF, 0xD2, 0xD5, 0xD9, 0xDC, 0xDF, 0xE3,
501     0xE6, 0xE9, 0xED, 0xF0, 0xF3, 0xF6, 0xFA, 0xFD,
502     0x03, 0x0B, 0x12, 0x18, 0x1D, 0x23, 0x28, 0x2D,
503     0x32, 0x36, 0x3B, 0x40, 0x44, 0x49, 0x4D, 0x51,
504     0x56, 0x5A, 0x5E, 0x62, 0x66, 0x6A, 0x6E, 0x72,
505     0x76, 0x7A, 0x7D, 0x81, 0x85, 0x89, 0x8D, 0x90,
506     0x94, 0x98, 0x9B, 0x9F, 0xA2, 0xA6, 0xAA, 0xAD,
507     0xB1, 0xB4, 0xB8, 0xBB, 0xBF, 0xC2, 0xC5, 0xC9,
508     0xCC, 0xD0, 0xD3, 0xD6, 0xDA, 0xDD, 0xE0, 0xE4,
509     0xE7, 0xEA, 0xED, 0xF1, 0xF4, 0xF7, 0xFA, 0xFD,
510     0x05, 0x0D, 0x13, 0x19, 0x1F, 0x24, 0x29, 0x2E,
511     0x33, 0x38, 0x3C, 0x41, 0x45, 0x4A, 0x4E, 0x52,
512     0x57, 0x5B, 0x5F, 0x63, 0x67, 0x6B, 0x6F, 0x73,
513     0x77, 0x7B, 0x7E, 0x82, 0x86, 0x8A, 0x8D, 0x91,
514     0x95, 0x99, 0x9C, 0xA0, 0xA3, 0xA7, 0xAA, 0xAE,
515     0xB2, 0xB5, 0xB9, 0xBC, 0xBF, 0xC3, 0xC6, 0xCA,
516     0xCD, 0xD0, 0xD4, 0xD7, 0xDA, 0xDE, 0xE1, 0xE4,
517     0xE8, 0xEB, 0xEE, 0xF1, 0xF5, 0xF8, 0xFB, 0xFD,
518     0x07, 0x0E, 0x15, 0x1A, 0x20, 0x25, 0x2A, 0x2F,
519     0x34, 0x39, 0x3D, 0x42, 0x46, 0x4B, 0x4F, 0x53,
520     0x58, 0x5C, 0x60, 0x64, 0x68, 0x6C, 0x70, 0x74,
521     0x78, 0x7C, 0x7F, 0x83, 0x87, 0x8B, 0x8E, 0x92,
522     0x96, 0x99, 0x9D, 0xA1, 0xA4, 0xA8, 0xAB, 0xAF,
523     0xB2, 0xB6, 0xB9, 0xBD, 0xC0, 0xC4, 0xC7, 0xCB,
524     0xCE, 0xD1, 0xD5, 0xD8, 0xDB, 0xDF, 0xE2, 0xE5,
525     0xE9, 0xEC, 0xEF, 0xF2, 0xF6, 0xF9, 0xFC, 0xFD
526 };
527 #endif
528
529 static int xan_decode_frame(AVCodecContext *avctx,
530                             void *data, int *got_frame,
531                             AVPacket *avpkt)
532 {
533     AVFrame *frame = data;
534     const uint8_t *buf = avpkt->data;
535     int ret, buf_size = avpkt->size;
536     XanContext *s = avctx->priv_data;
537     GetByteContext ctx;
538     int tag = 0;
539
540     bytestream2_init(&ctx, buf, buf_size);
541     while (bytestream2_get_bytes_left(&ctx) > 8 && tag != VGA__TAG) {
542         unsigned *tmpptr;
543         uint32_t new_pal;
544         int size;
545         int i;
546         tag  = bytestream2_get_le32(&ctx);
547         size = bytestream2_get_be32(&ctx);
548         if(size < 0) {
549             av_log(avctx, AV_LOG_ERROR, "Invalid tag size %d\n", size);
550             return AVERROR_INVALIDDATA;
551         }
552         size = FFMIN(size, bytestream2_get_bytes_left(&ctx));
553         switch (tag) {
554         case PALT_TAG:
555             if (size < PALETTE_SIZE)
556                 return AVERROR_INVALIDDATA;
557             if (s->palettes_count >= PALETTES_MAX)
558                 return AVERROR_INVALIDDATA;
559             tmpptr = av_realloc(s->palettes,
560                                 (s->palettes_count + 1) * AVPALETTE_SIZE);
561             if (!tmpptr)
562                 return AVERROR(ENOMEM);
563             s->palettes = tmpptr;
564             tmpptr += s->palettes_count * AVPALETTE_COUNT;
565             for (i = 0; i < PALETTE_COUNT; i++) {
566 #if RUNTIME_GAMMA
567                 int r = gamma_corr(bytestream2_get_byteu(&ctx));
568                 int g = gamma_corr(bytestream2_get_byteu(&ctx));
569                 int b = gamma_corr(bytestream2_get_byteu(&ctx));
570 #else
571                 int r = gamma_lookup[bytestream2_get_byteu(&ctx)];
572                 int g = gamma_lookup[bytestream2_get_byteu(&ctx)];
573                 int b = gamma_lookup[bytestream2_get_byteu(&ctx)];
574 #endif
575                 *tmpptr++ = (0xFFU << 24) | (r << 16) | (g << 8) | b;
576             }
577             s->palettes_count++;
578             break;
579         case SHOT_TAG:
580             if (size < 4)
581                 return AVERROR_INVALIDDATA;
582             new_pal = bytestream2_get_le32(&ctx);
583             if (new_pal < s->palettes_count) {
584                 s->cur_palette = new_pal;
585             } else
586                 av_log(avctx, AV_LOG_ERROR, "Invalid palette selected\n");
587             break;
588         case VGA__TAG:
589             break;
590         default:
591             bytestream2_skip(&ctx, size);
592             break;
593         }
594     }
595     buf_size = bytestream2_get_bytes_left(&ctx);
596
597     if (s->palettes_count <= 0) {
598         av_log(s->avctx, AV_LOG_ERROR, "No palette found\n");
599         return AVERROR_INVALIDDATA;
600     }
601
602     if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
603         return ret;
604
605     if (!s->frame_size)
606         s->frame_size = frame->linesize[0] * s->avctx->height;
607
608     memcpy(frame->data[1],
609            s->palettes + s->cur_palette * AVPALETTE_COUNT, AVPALETTE_SIZE);
610
611     s->buf = ctx.buffer;
612     s->size = buf_size;
613
614     if (xan_wc3_decode_frame(s, frame) < 0)
615         return AVERROR_INVALIDDATA;
616
617     av_frame_unref(s->last_frame);
618     if ((ret = av_frame_ref(s->last_frame, frame)) < 0)
619         return ret;
620
621     *got_frame = 1;
622
623     /* always report that the buffer was completely consumed */
624     return buf_size;
625 }
626
627 static av_cold int xan_decode_end(AVCodecContext *avctx)
628 {
629     XanContext *s = avctx->priv_data;
630
631     av_frame_free(&s->last_frame);
632
633     av_freep(&s->buffer1);
634     av_freep(&s->buffer2);
635     av_freep(&s->palettes);
636
637     return 0;
638 }
639
640 AVCodec ff_xan_wc3_decoder = {
641     .name           = "xan_wc3",
642     .long_name      = NULL_IF_CONFIG_SMALL("Wing Commander III / Xan"),
643     .type           = AVMEDIA_TYPE_VIDEO,
644     .id             = AV_CODEC_ID_XAN_WC3,
645     .priv_data_size = sizeof(XanContext),
646     .init           = xan_decode_init,
647     .close          = xan_decode_end,
648     .decode         = xan_decode_frame,
649     .capabilities   = CODEC_CAP_DR1,
650 };