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