FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/argo.c
Date: 2025-09-24 17:43:11
Exec Total Coverage
Lines: 0 473 0.0%
Functions: 0 10 0.0%
Branches: 0 284 0.0%

Line Branch Exec Source
1 /*
2 * Argonaut Games Video decoder
3 * Copyright (c) 2020 Paul B Mahol
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 #include <string.h>
23
24 #include "libavutil/attributes.h"
25 #include "libavutil/internal.h"
26 #include "libavutil/intreadwrite.h"
27
28 #include "avcodec.h"
29 #include "bytestream.h"
30 #include "codec_internal.h"
31 #include "decode.h"
32
33 typedef struct ArgoContext {
34 GetByteContext gb;
35
36 int bpp;
37 int key;
38 int mv0[128][2];
39 int mv1[16][2];
40 uint32_t pal[256];
41 AVFrame *frame;
42 } ArgoContext;
43
44 static int decode_pal8(AVCodecContext *avctx, uint32_t *pal)
45 {
46 ArgoContext *s = avctx->priv_data;
47 GetByteContext *gb = &s->gb;
48 int start, count;
49
50 start = bytestream2_get_le16(gb);
51 count = bytestream2_get_le16(gb);
52
53 if (start + count > 256)
54 return AVERROR_INVALIDDATA;
55
56 if (bytestream2_get_bytes_left(gb) < 3 * count)
57 return AVERROR_INVALIDDATA;
58
59 for (int i = 0; i < count; i++)
60 pal[start + i] = (0xFFU << 24) | bytestream2_get_be24u(gb);
61
62 return 0;
63 }
64
65 static int decode_avcf(AVCodecContext *avctx, AVFrame *frame)
66 {
67 ArgoContext *s = avctx->priv_data;
68 GetByteContext *gb = &s->gb;
69 const int l = frame->linesize[0];
70 const uint8_t *map = gb->buffer;
71 uint8_t *dst = frame->data[0];
72
73 if (bytestream2_get_bytes_left(gb) < 1024 + (frame->width / 2) * (frame->height / 2))
74 return AVERROR_INVALIDDATA;
75
76 bytestream2_skipu(gb, 1024);
77 for (int y = 0; y < frame->height; y += 2) {
78 for (int x = 0; x < frame->width; x += 2) {
79 int index = bytestream2_get_byteu(gb);
80 const uint8_t *block = map + index * 4;
81
82 dst[x+0] = block[0];
83 dst[x+1] = block[1];
84 dst[x+l] = block[2];
85 dst[x+l+1] = block[3];
86 }
87
88 dst += frame->linesize[0] * 2;
89 }
90
91 return 0;
92 }
93
94 static int decode_alcd(AVCodecContext *avctx, AVFrame *frame)
95 {
96 ArgoContext *s = avctx->priv_data;
97 GetByteContext *gb = &s->gb;
98 GetByteContext sb;
99 const int l = frame->linesize[0];
100 const uint8_t *map = gb->buffer;
101 uint8_t *dst = frame->data[0];
102 uint8_t codes = 0;
103 int count = 0;
104
105 if (bytestream2_get_bytes_left(gb) < 1024 + (((frame->width / 2) * (frame->height / 2) + 7) >> 3))
106 return AVERROR_INVALIDDATA;
107
108 bytestream2_skipu(gb, 1024);
109 sb = *gb;
110 bytestream2_skipu(gb, ((frame->width / 2) * (frame->height / 2) + 7) >> 3);
111
112 for (int y = 0; y < frame->height; y += 2) {
113 for (int x = 0; x < frame->width; x += 2) {
114 const uint8_t *block;
115 int index;
116
117 if (count == 0) {
118 codes = bytestream2_get_byteu(&sb);
119 count = 8;
120 }
121
122 if (codes & 0x80) {
123 index = bytestream2_get_byte(gb);
124 block = map + index * 4;
125
126 dst[x+0] = block[0];
127 dst[x+1] = block[1];
128 dst[x+l] = block[2];
129 dst[x+l+1] = block[3];
130 }
131
132 codes <<= 1;
133 count--;
134 }
135
136 dst += frame->linesize[0] * 2;
137 }
138
139 return 0;
140 }
141
142 static int decode_mad1(AVCodecContext *avctx, AVFrame *frame)
143 {
144 ArgoContext *s = avctx->priv_data;
145 GetByteContext *gb = &s->gb;
146 const int w = frame->width;
147 const int h = frame->height;
148 const int l = frame->linesize[0];
149
150 while (bytestream2_get_bytes_left(gb) > 0) {
151 int size, type, pos, dy;
152 uint8_t *dst;
153
154 type = bytestream2_get_byte(gb);
155 if (type == 0xFF)
156 break;
157
158 switch (type) {
159 case 8:
160 dst = frame->data[0];
161 for (int y = 0; y < h; y += 8) {
162 for (int x = 0; x < w; x += 8) {
163 int fill = bytestream2_get_byte(gb);
164 uint8_t *ddst = dst + x;
165
166 for (int by = 0; by < 8; by++) {
167 memset(ddst, fill, 8);
168 ddst += l;
169 }
170 }
171
172 dst += 8 * l;
173 }
174 break;
175 case 7:
176 while (bytestream2_get_bytes_left(gb) > 0) {
177 int bsize = bytestream2_get_byte(gb);
178 uint8_t *src;
179 int count;
180
181 if (!bsize)
182 break;
183
184 count = bytestream2_get_be16(gb);
185 while (count > 0) {
186 int mvx, mvy, a, b, c, mx, my;
187 int bsize_w, bsize_h;
188
189 bsize_w = bsize_h = bsize;
190 if (bytestream2_get_bytes_left(gb) < 4)
191 return AVERROR_INVALIDDATA;
192 mvx = bytestream2_get_byte(gb) * bsize;
193 mvy = bytestream2_get_byte(gb) * bsize;
194 a = bytestream2_get_byte(gb);
195 b = bytestream2_get_byte(gb);
196 c = ((a & 0x3F) << 8) + b;
197 mx = mvx + (c & 0x7F) - 64;
198 my = mvy + (c >> 7) - 64;
199
200 if (mvy < 0 || mvy >= h)
201 return AVERROR_INVALIDDATA;
202
203 if (mvx < 0 || mvx >= w)
204 return AVERROR_INVALIDDATA;
205
206 if (my < 0 || my >= h)
207 return AVERROR_INVALIDDATA;
208
209 if (mx < 0 || mx >= w)
210 return AVERROR_INVALIDDATA;
211
212 dst = frame->data[0] + mvx + l * mvy;
213 src = frame->data[0] + mx + l * my;
214
215 bsize_w = FFMIN3(bsize_w, w - mvx, w - mx);
216 bsize_h = FFMIN3(bsize_h, h - mvy, h - my);
217
218 if (mvy >= my && (mvy != my || mvx >= mx)) {
219 src += (bsize_h - 1) * l;
220 dst += (bsize_h - 1) * l;
221 for (int by = 0; by < bsize_h; by++) {
222 memmove(dst, src, bsize_w);
223 src -= l;
224 dst -= l;
225 }
226 } else {
227 for (int by = 0; by < bsize_h; by++) {
228 memmove(dst, src, bsize_w);
229 src += l;
230 dst += l;
231 }
232 }
233
234 count--;
235 }
236 }
237 break;
238 case 6:
239 dst = frame->data[0];
240 if (bytestream2_get_bytes_left(gb) < w * h)
241 return AVERROR_INVALIDDATA;
242 for (int y = 0; y < h; y++) {
243 bytestream2_get_bufferu(gb, dst, w);
244 dst += l;
245 }
246 break;
247 case 5:
248 dst = frame->data[0];
249 for (int y = 0; y < h; y += 2) {
250 for (int x = 0; x < w; x += 2) {
251 int fill = bytestream2_get_byte(gb);
252 uint8_t *ddst = dst + x;
253
254 fill = (fill << 8) | fill;
255 for (int by = 0; by < 2; by++) {
256 AV_WN16(ddst, fill);
257
258 ddst += l;
259 }
260 }
261
262 dst += 2 * l;
263 }
264 break;
265 case 3:
266 size = bytestream2_get_le16(gb);
267 if (size > 0) {
268 int x = bytestream2_get_byte(gb) * 4;
269 int y = bytestream2_get_byte(gb) * 4;
270 int count = bytestream2_get_byte(gb);
271 int fill = bytestream2_get_byte(gb);
272
273 av_log(avctx, AV_LOG_DEBUG, "%d %d %d %d\n", x, y, count, fill);
274 for (int i = 0; i < count; i++)
275 ;
276 return AVERROR_PATCHWELCOME;
277 }
278 break;
279 case 2:
280 dst = frame->data[0];
281 pos = 0;
282 dy = 0;
283 while (bytestream2_get_bytes_left(gb) > 0) {
284 int count = bytestream2_get_byteu(gb);
285 int skip = count & 0x3F;
286
287 count = count >> 6;
288 if (skip == 0x3F) {
289 pos += 0x3E;
290 while (pos >= w) {
291 pos -= w;
292 dst += l;
293 dy++;
294 if (dy >= h)
295 return 0;
296 }
297 } else {
298 pos += skip;
299 while (pos >= w) {
300 pos -= w;
301 dst += l;
302 dy++;
303 if (dy >= h)
304 return 0;
305 }
306 while (count >= 0) {
307 int bits = bytestream2_get_byte(gb);
308
309 for (int i = 0; i < 4; i++) {
310 switch (bits & 3) {
311 case 0:
312 break;
313 case 1:
314 if (dy < 1 && !pos)
315 return AVERROR_INVALIDDATA;
316 else
317 dst[pos] = pos ? dst[pos - 1] : dst[-l + w - 1];
318 break;
319 case 2:
320 if (dy < 1)
321 return AVERROR_INVALIDDATA;
322 dst[pos] = dst[pos - l];
323 break;
324 case 3:
325 dst[pos] = bytestream2_get_byte(gb);
326 break;
327 }
328
329 pos++;
330 if (pos >= w) {
331 pos -= w;
332 dst += l;
333 dy++;
334 if (dy >= h)
335 return 0;
336 }
337 bits >>= 2;
338 }
339 count--;
340 }
341 }
342 }
343 break;
344 default:
345 return AVERROR_INVALIDDATA;
346 }
347 }
348
349 return 0;
350 }
351
352 static int decode_mad1_24(AVCodecContext *avctx, AVFrame *frame)
353 {
354 ArgoContext *s = avctx->priv_data;
355 GetByteContext *gb = &s->gb;
356 const int w = frame->width;
357 const int h = frame->height;
358 const int l = frame->linesize[0] / 4;
359
360 while (bytestream2_get_bytes_left(gb) > 0) {
361 int osize, type, pos, dy, di, bcode, value, v14;
362 const uint8_t *bits;
363 uint32_t *dst;
364
365 type = bytestream2_get_byte(gb);
366 if (type == 0xFF)
367 return 0;
368
369 switch (type) {
370 case 8:
371 dst = (uint32_t *)frame->data[0];
372 for (int y = 0; y + 12 <= h; y += 12) {
373 for (int x = 0; x + 12 <= w; x += 12) {
374 int fill = bytestream2_get_be24(gb);
375 uint32_t *dstp = dst + x;
376
377 for (int by = 0; by < 12; by++) {
378 for (int bx = 0; bx < 12; bx++)
379 dstp[bx] = fill;
380
381 dstp += l;
382 }
383 }
384
385 dst += 12 * l;
386 }
387 break;
388 case 7:
389 while (bytestream2_get_bytes_left(gb) > 0) {
390 int bsize = bytestream2_get_byte(gb);
391 uint32_t *src;
392 int count;
393
394 if (!bsize)
395 break;
396
397 count = bytestream2_get_be16(gb);
398 while (count > 0) {
399 int mvx, mvy, a, b, c, mx, my;
400 int bsize_w, bsize_h;
401
402 bsize_w = bsize_h = bsize;
403 if (bytestream2_get_bytes_left(gb) < 4)
404 return AVERROR_INVALIDDATA;
405 mvx = bytestream2_get_byte(gb) * bsize;
406 mvy = bytestream2_get_byte(gb) * bsize;
407 a = bytestream2_get_byte(gb);
408 b = bytestream2_get_byte(gb);
409 c = ((a & 0x3F) << 8) + b;
410 mx = mvx + (c & 0x7F) - 64;
411 my = mvy + (c >> 7) - 64;
412
413 if (mvy < 0 || mvy >= h)
414 return AVERROR_INVALIDDATA;
415
416 if (mvx < 0 || mvx >= w)
417 return AVERROR_INVALIDDATA;
418
419 if (my < 0 || my >= h)
420 return AVERROR_INVALIDDATA;
421
422 if (mx < 0 || mx >= w)
423 return AVERROR_INVALIDDATA;
424
425 dst = (uint32_t *)frame->data[0] + mvx + l * mvy;
426 src = (uint32_t *)frame->data[0] + mx + l * my;
427
428 bsize_w = FFMIN3(bsize_w, w - mvx, w - mx);
429 bsize_h = FFMIN3(bsize_h, h - mvy, h - my);
430
431 if (mvy >= my && (mvy != my || mvx >= mx)) {
432 src += (bsize_h - 1) * l;
433 dst += (bsize_h - 1) * l;
434 for (int by = 0; by < bsize_h; by++) {
435 memmove(dst, src, bsize_w * 4);
436 src -= l;
437 dst -= l;
438 }
439 } else {
440 for (int by = 0; by < bsize_h; by++) {
441 memmove(dst, src, bsize_w * 4);
442 src += l;
443 dst += l;
444 }
445 }
446
447 count--;
448 }
449 }
450 break;
451 case 12:
452 osize = ((h + 3) / 4) * ((w + 3) / 4) + 7;
453 bits = gb->buffer;
454 di = 0;
455 bcode = v14 = 0;
456 if (bytestream2_get_bytes_left(gb) < osize >> 3)
457 return AVERROR_INVALIDDATA;
458 bytestream2_skip(gb, osize >> 3);
459 for (int x = 0; x < w; x += 4) {
460 for (int y = 0; y < h; y += 4) {
461 int astate = 0;
462
463 if (bits[di >> 3] & (1 << (di & 7))) {
464 int codes = bytestream2_get_byte(gb);
465
466 for (int count = 0; count < 4; count++) {
467 uint32_t *src = (uint32_t *)frame->data[0];
468 size_t src_size = l * (h - 1) + (w - 1);
469 int nv, v, code = codes & 3;
470
471 pos = x;
472 dy = y + count;
473 dst = (uint32_t *)frame->data[0] + pos + dy * l;
474 if (code & 1)
475 bcode = bytestream2_get_byte(gb);
476 if (code == 3) {
477 for (int j = 0; j < 4; j++) {
478 switch (bcode & 3) {
479 case 0:
480 break;
481 case 1:
482 if (dy < 1 && !pos)
483 return AVERROR_INVALIDDATA;
484 dst[0] = dst[-1];
485 break;
486 case 2:
487 if (dy < 1)
488 return AVERROR_INVALIDDATA;
489 dst[0] = dst[-l];
490 break;
491 case 3:
492 if (astate) {
493 nv = value >> 4;
494 } else {
495 value = bytestream2_get_byte(gb);
496 nv = value & 0xF;
497 }
498 astate ^= 1;
499 dst[0] = src[av_clip(l * (dy + s->mv1[nv][1]) + pos +
500 s->mv1[nv][0], 0, src_size)];
501 break;
502 }
503
504 bcode >>= 2;
505 dst++;
506 pos++;
507 }
508 } else if (code) {
509 if (code == 1)
510 v14 = bcode;
511 else
512 bcode = v14;
513 for (int j = 0; j < 4; j++) {
514 switch (bcode & 3) {
515 case 0:
516 break;
517 case 1:
518 if (dy < 1 && !pos)
519 return AVERROR_INVALIDDATA;
520 dst[0] = dst[-1];
521 break;
522 case 2:
523 if (dy < 1)
524 return AVERROR_INVALIDDATA;
525 dst[0] = dst[-l];
526 break;
527 case 3:
528 v = bytestream2_get_byte(gb);
529 if (v < 128) {
530 dst[0] = src[av_clip(l * (dy + s->mv0[v][1]) + pos +
531 s->mv0[v][0], 0, src_size)];
532 } else {
533 dst[0] = ((v & 0x7F) << 17) | bytestream2_get_be16(gb);
534 }
535 break;
536 }
537
538 bcode >>= 2;
539 dst++;
540 pos++;
541 }
542 }
543
544 codes >>= 2;
545 }
546 }
547
548 di++;
549 }
550 }
551 break;
552 default:
553 return AVERROR_INVALIDDATA;
554 }
555 }
556
557 return AVERROR_INVALIDDATA;
558 }
559
560 static int decode_rle(AVCodecContext *avctx, AVFrame *frame)
561 {
562 ArgoContext *s = avctx->priv_data;
563 GetByteContext *gb = &s->gb;
564 const int w = frame->width;
565 const int h = frame->height;
566 const int l = frame->linesize[0];
567 uint8_t *dst = frame->data[0];
568 int pos = 0, y = 0;
569
570 while (bytestream2_get_bytes_left(gb) > 0) {
571 int count = bytestream2_get_byte(gb);
572 int pixel = bytestream2_get_byte(gb);
573
574 if (!count) {
575 pos += pixel;
576 while (pos >= w) {
577 pos -= w;
578 y++;
579 if (y >= h)
580 return 0;
581 }
582 } else {
583 while (count > 0) {
584 dst[pos + y * l] = pixel;
585 count--;
586 pos++;
587 if (pos >= w) {
588 pos = 0;
589 y++;
590 if (y >= h)
591 return 0;
592 }
593 }
594 }
595 }
596
597 return 0;
598 }
599
600 static int decode_frame(AVCodecContext *avctx, AVFrame *rframe,
601 int *got_frame, AVPacket *avpkt)
602 {
603 ArgoContext *s = avctx->priv_data;
604 GetByteContext *gb = &s->gb;
605 AVFrame *frame = s->frame;
606 uint32_t chunk;
607 int ret;
608
609 if (avpkt->size < 4)
610 return AVERROR_INVALIDDATA;
611
612 bytestream2_init(gb, avpkt->data, avpkt->size);
613
614 if ((ret = ff_reget_buffer(avctx, frame, 0)) < 0)
615 return ret;
616
617 chunk = bytestream2_get_be32(gb);
618 switch (chunk) {
619 case MKBETAG('P', 'A', 'L', '8'):
620 for (int y = 0; y < frame->height; y++)
621 memset(frame->data[0] + y * frame->linesize[0], 0, frame->width * s->bpp);
622 if (avctx->pix_fmt == AV_PIX_FMT_PAL8)
623 memset(frame->data[1], 0, AVPALETTE_SIZE);
624 return decode_pal8(avctx, s->pal);
625 case MKBETAG('M', 'A', 'D', '1'):
626 if (avctx->pix_fmt == AV_PIX_FMT_PAL8)
627 ret = decode_mad1(avctx, frame);
628 else
629 ret = decode_mad1_24(avctx, frame);
630 break;
631 case MKBETAG('A', 'V', 'C', 'F'):
632 if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
633 s->key = 1;
634 ret = decode_avcf(avctx, frame);
635 break;
636 }
637 case MKBETAG('A', 'L', 'C', 'D'):
638 if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
639 s->key = 0;
640 ret = decode_alcd(avctx, frame);
641 break;
642 }
643 case MKBETAG('R', 'L', 'E', 'F'):
644 if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
645 s->key = 1;
646 ret = decode_rle(avctx, frame);
647 break;
648 }
649 case MKBETAG('R', 'L', 'E', 'D'):
650 if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
651 s->key = 0;
652 ret = decode_rle(avctx, frame);
653 break;
654 }
655 default:
656 av_log(avctx, AV_LOG_DEBUG, "unknown chunk 0x%X\n", chunk);
657 break;
658 }
659
660 if (ret < 0)
661 return ret;
662
663 if (avctx->pix_fmt == AV_PIX_FMT_PAL8)
664 memcpy(frame->data[1], s->pal, AVPALETTE_SIZE);
665
666 if ((ret = av_frame_ref(rframe, s->frame)) < 0)
667 return ret;
668
669 frame->pict_type = s->key ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
670 if (s->key)
671 frame->flags |= AV_FRAME_FLAG_KEY;
672 else
673 frame->flags &= ~AV_FRAME_FLAG_KEY;
674 *got_frame = 1;
675
676 return avpkt->size;
677 }
678
679 static av_cold int decode_init(AVCodecContext *avctx)
680 {
681 ArgoContext *s = avctx->priv_data;
682
683 switch (avctx->bits_per_coded_sample) {
684 case 8: s->bpp = 1;
685 avctx->pix_fmt = AV_PIX_FMT_PAL8; break;
686 case 24: s->bpp = 4;
687 avctx->pix_fmt = AV_PIX_FMT_BGR0; break;
688 default: avpriv_request_sample(s, "depth == %u", avctx->bits_per_coded_sample);
689 return AVERROR_PATCHWELCOME;
690 }
691
692 if (avctx->width % 2 || avctx->height % 2) {
693 avpriv_request_sample(s, "Odd dimensions\n");
694 return AVERROR_PATCHWELCOME;
695 }
696
697 s->frame = av_frame_alloc();
698 if (!s->frame)
699 return AVERROR(ENOMEM);
700
701 for (int n = 0, i = -4; i < 4; i++) {
702 for (int j = -14; j < 2; j++) {
703 s->mv0[n][0] = j;
704 s->mv0[n++][1] = i;
705 }
706 }
707
708 for (int n = 0, i = -5; i <= 1; i += 2) {
709 int j = -5;
710
711 while (j <= 1) {
712 s->mv1[n][0] = j;
713 s->mv1[n++][1] = i;
714 j += 2;
715 }
716 }
717
718 return 0;
719 }
720
721 static av_cold void decode_flush(AVCodecContext *avctx)
722 {
723 ArgoContext *s = avctx->priv_data;
724
725 av_frame_unref(s->frame);
726 }
727
728 static av_cold int decode_close(AVCodecContext *avctx)
729 {
730 ArgoContext *s = avctx->priv_data;
731
732 av_frame_free(&s->frame);
733
734 return 0;
735 }
736
737 const FFCodec ff_argo_decoder = {
738 .p.name = "argo",
739 CODEC_LONG_NAME("Argonaut Games Video"),
740 .p.type = AVMEDIA_TYPE_VIDEO,
741 .p.id = AV_CODEC_ID_ARGO,
742 .priv_data_size = sizeof(ArgoContext),
743 .init = decode_init,
744 FF_CODEC_DECODE_CB(decode_frame),
745 .flush = decode_flush,
746 .close = decode_close,
747 .p.capabilities = AV_CODEC_CAP_DR1,
748 .caps_internal = FF_CODEC_CAP_INIT_CLEANUP,
749 };
750