FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/xan.c
Date: 2026-09-28 17:50:41
Exec Total Coverage
Lines: 243 287 84.7%
Functions: 8 8 100.0%
Branches: 95 149 63.8%

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