FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/xan.c
Date: 2024-04-18 10:05:09
Exec Total Coverage
Lines: 243 287 84.7%
Functions: 8 8 100.0%
Branches: 94 147 63.9%

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