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