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