2 * Argonaut Games Video decoder
3 * Copyright (c) 2020 Paul B Mahol
5 * This file is part of FFmpeg.
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.
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.
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
24 #include "libavutil/internal.h"
25 #include "libavutil/intreadwrite.h"
28 #include "bytestream.h"
29 #include "codec_internal.h"
32 typedef struct ArgoContext {
43 static int decode_pal8(AVCodecContext *avctx, uint32_t *pal)
45 ArgoContext *s = avctx->priv_data;
46 GetByteContext *gb = &s->gb;
49 start = bytestream2_get_le16(gb);
50 count = bytestream2_get_le16(gb);
52 if (start + count > 256)
53 return AVERROR_INVALIDDATA;
55 if (bytestream2_get_bytes_left(gb) < 3 * count)
56 return AVERROR_INVALIDDATA;
58 for (int i = 0; i < count; i++)
59 pal[start + i] = (0xFFU << 24) | bytestream2_get_be24u(gb);
64 static int decode_avcf(AVCodecContext *avctx, AVFrame *frame)
66 ArgoContext *s = avctx->priv_data;
67 GetByteContext *gb = &s->gb;
68 const int l = frame->linesize[0];
69 const uint8_t *map = gb->buffer;
70 uint8_t *dst = frame->data[0];
72 if (bytestream2_get_bytes_left(gb) < 1024 + (frame->width / 2) * (frame->height / 2))
73 return AVERROR_INVALIDDATA;
75 bytestream2_skipu(gb, 1024);
76 for (int y = 0; y < frame->height; y += 2) {
77 for (int x = 0; x < frame->width; x += 2) {
78 int index = bytestream2_get_byteu(gb);
79 const uint8_t *block = map + index * 4;
84 dst[x+l+1] = block[3];
87 dst += frame->linesize[0] * 2;
93 static int decode_alcd(AVCodecContext *avctx, AVFrame *frame)
95 ArgoContext *s = avctx->priv_data;
96 GetByteContext *gb = &s->gb;
98 const int l = frame->linesize[0];
99 const uint8_t *map = gb->buffer;
100 uint8_t *dst = frame->data[0];
104 if (bytestream2_get_bytes_left(gb) < 1024 + (((frame->width / 2) * (frame->height / 2) + 7) >> 3))
105 return AVERROR_INVALIDDATA;
107 bytestream2_skipu(gb, 1024);
109 bytestream2_skipu(gb, ((frame->width / 2) * (frame->height / 2) + 7) >> 3);
111 for (int y = 0; y < frame->height; y += 2) {
112 for (int x = 0; x < frame->width; x += 2) {
113 const uint8_t *block;
117 codes = bytestream2_get_byteu(&sb);
122 index = bytestream2_get_byte(gb);
123 block = map + index * 4;
128 dst[x+l+1] = block[3];
135 dst += frame->linesize[0] * 2;
141 static int decode_mad1(AVCodecContext *avctx, AVFrame *frame)
143 ArgoContext *s = avctx->priv_data;
144 GetByteContext *gb = &s->gb;
145 const int w = frame->width;
146 const int h = frame->height;
147 const int l = frame->linesize[0];
149 while (bytestream2_get_bytes_left(gb) > 0) {
150 int size, type, pos, dy;
153 type = bytestream2_get_byte(gb);
159 dst = frame->data[0];
160 for (int y = 0; y < h; y += 8) {
161 for (int x = 0; x < w; x += 8) {
162 int fill = bytestream2_get_byte(gb);
163 uint8_t *ddst = dst + x;
165 for (int by = 0; by < 8; by++) {
166 memset(ddst, fill, 8);
175 while (bytestream2_get_bytes_left(gb) > 0) {
176 int bsize = bytestream2_get_byte(gb);
183 count = bytestream2_get_be16(gb);
185 int mvx, mvy, a, b, c, mx, my;
186 int bsize_w, bsize_h;
188 bsize_w = bsize_h = bsize;
189 if (bytestream2_get_bytes_left(gb) < 4)
190 return AVERROR_INVALIDDATA;
191 mvx = bytestream2_get_byte(gb) * bsize;
192 mvy = bytestream2_get_byte(gb) * bsize;
193 a = bytestream2_get_byte(gb);
194 b = bytestream2_get_byte(gb);
195 c = ((a & 0x3F) << 8) + b;
196 mx = mvx + (c & 0x7F) - 64;
197 my = mvy + (c >> 7) - 64;
199 if (mvy < 0 || mvy >= h)
200 return AVERROR_INVALIDDATA;
202 if (mvx < 0 || mvx >= w)
203 return AVERROR_INVALIDDATA;
205 if (my < 0 || my >= h)
206 return AVERROR_INVALIDDATA;
208 if (mx < 0 || mx >= w)
209 return AVERROR_INVALIDDATA;
211 dst = frame->data[0] + mvx + l * mvy;
212 src = frame->data[0] + mx + l * my;
214 bsize_w = FFMIN3(bsize_w, w - mvx, w - mx);
215 bsize_h = FFMIN3(bsize_h, h - mvy, h - my);
217 if (mvy >= my && (mvy != my || mvx >= mx)) {
218 src += (bsize_h - 1) * l;
219 dst += (bsize_h - 1) * l;
220 for (int by = 0; by < bsize_h; by++) {
221 memmove(dst, src, bsize_w);
226 for (int by = 0; by < bsize_h; by++) {
227 memmove(dst, src, bsize_w);
238 dst = frame->data[0];
239 if (bytestream2_get_bytes_left(gb) < w * h)
240 return AVERROR_INVALIDDATA;
241 for (int y = 0; y < h; y++) {
242 bytestream2_get_bufferu(gb, dst, w);
247 dst = frame->data[0];
248 for (int y = 0; y < h; y += 2) {
249 for (int x = 0; x < w; x += 2) {
250 int fill = bytestream2_get_byte(gb);
251 uint8_t *ddst = dst + x;
253 fill = (fill << 8) | fill;
254 for (int by = 0; by < 2; by++) {
265 size = bytestream2_get_le16(gb);
267 int x = bytestream2_get_byte(gb) * 4;
268 int y = bytestream2_get_byte(gb) * 4;
269 int count = bytestream2_get_byte(gb);
270 int fill = bytestream2_get_byte(gb);
272 av_log(avctx, AV_LOG_DEBUG, "%d %d %d %d\n", x, y, count, fill);
273 for (int i = 0; i < count; i++)
275 return AVERROR_PATCHWELCOME;
279 dst = frame->data[0];
282 while (bytestream2_get_bytes_left(gb) > 0) {
283 int count = bytestream2_get_byteu(gb);
284 int skip = count & 0x3F;
306 int bits = bytestream2_get_byte(gb);
308 for (int i = 0; i < 4; i++) {
314 return AVERROR_INVALIDDATA;
316 dst[pos] = pos ? dst[pos - 1] : dst[-l + w - 1];
320 return AVERROR_INVALIDDATA;
321 dst[pos] = dst[pos - l];
324 dst[pos] = bytestream2_get_byte(gb);
344 return AVERROR_INVALIDDATA;
351 static int decode_mad1_24(AVCodecContext *avctx, AVFrame *frame)
353 ArgoContext *s = avctx->priv_data;
354 GetByteContext *gb = &s->gb;
355 const int w = frame->width;
356 const int h = frame->height;
357 const int l = frame->linesize[0] / 4;
359 while (bytestream2_get_bytes_left(gb) > 0) {
360 int osize, type, pos, dy, di, bcode, value, v14;
364 type = bytestream2_get_byte(gb);
370 dst = (uint32_t *)frame->data[0];
371 for (int y = 0; y + 12 <= h; y += 12) {
372 for (int x = 0; x + 12 <= w; x += 12) {
373 int fill = bytestream2_get_be24(gb);
374 uint32_t *dstp = dst + x;
376 for (int by = 0; by < 12; by++) {
377 for (int bx = 0; bx < 12; bx++)
388 while (bytestream2_get_bytes_left(gb) > 0) {
389 int bsize = bytestream2_get_byte(gb);
396 count = bytestream2_get_be16(gb);
398 int mvx, mvy, a, b, c, mx, my;
399 int bsize_w, bsize_h;
401 bsize_w = bsize_h = bsize;
402 if (bytestream2_get_bytes_left(gb) < 4)
403 return AVERROR_INVALIDDATA;
404 mvx = bytestream2_get_byte(gb) * bsize;
405 mvy = bytestream2_get_byte(gb) * bsize;
406 a = bytestream2_get_byte(gb);
407 b = bytestream2_get_byte(gb);
408 c = ((a & 0x3F) << 8) + b;
409 mx = mvx + (c & 0x7F) - 64;
410 my = mvy + (c >> 7) - 64;
412 if (mvy < 0 || mvy >= h)
413 return AVERROR_INVALIDDATA;
415 if (mvx < 0 || mvx >= w)
416 return AVERROR_INVALIDDATA;
418 if (my < 0 || my >= h)
419 return AVERROR_INVALIDDATA;
421 if (mx < 0 || mx >= w)
422 return AVERROR_INVALIDDATA;
424 dst = (uint32_t *)frame->data[0] + mvx + l * mvy;
425 src = (uint32_t *)frame->data[0] + mx + l * my;
427 bsize_w = FFMIN3(bsize_w, w - mvx, w - mx);
428 bsize_h = FFMIN3(bsize_h, h - mvy, h - my);
430 if (mvy >= my && (mvy != my || mvx >= mx)) {
431 src += (bsize_h - 1) * l;
432 dst += (bsize_h - 1) * l;
433 for (int by = 0; by < bsize_h; by++) {
434 memmove(dst, src, bsize_w * 4);
439 for (int by = 0; by < bsize_h; by++) {
440 memmove(dst, src, bsize_w * 4);
451 osize = ((h + 3) / 4) * ((w + 3) / 4) + 7;
455 if (bytestream2_get_bytes_left(gb) < osize >> 3)
456 return AVERROR_INVALIDDATA;
457 bytestream2_skip(gb, osize >> 3);
458 for (int x = 0; x < w; x += 4) {
459 for (int y = 0; y < h; y += 4) {
462 if (bits[di >> 3] & (1 << (di & 7))) {
463 int codes = bytestream2_get_byte(gb);
465 for (int count = 0; count < 4; count++) {
466 uint32_t *src = (uint32_t *)frame->data[0];
467 size_t src_size = l * (h - 1) + (w - 1);
468 int nv, v, code = codes & 3;
472 dst = (uint32_t *)frame->data[0] + pos + dy * l;
474 bcode = bytestream2_get_byte(gb);
476 for (int j = 0; j < 4; j++) {
482 return AVERROR_INVALIDDATA;
487 return AVERROR_INVALIDDATA;
494 value = bytestream2_get_byte(gb);
498 dst[0] = src[av_clip(l * (dy + s->mv1[nv][1]) + pos +
499 s->mv1[nv][0], 0, src_size)];
512 for (int j = 0; j < 4; j++) {
518 return AVERROR_INVALIDDATA;
523 return AVERROR_INVALIDDATA;
527 v = bytestream2_get_byte(gb);
529 dst[0] = src[av_clip(l * (dy + s->mv0[v][1]) + pos +
530 s->mv0[v][0], 0, src_size)];
532 dst[0] = ((v & 0x7F) << 17) | bytestream2_get_be16(gb);
552 return AVERROR_INVALIDDATA;
556 return AVERROR_INVALIDDATA;
559 static int decode_rle(AVCodecContext *avctx, AVFrame *frame)
561 ArgoContext *s = avctx->priv_data;
562 GetByteContext *gb = &s->gb;
563 const int w = frame->width;
564 const int h = frame->height;
565 const int l = frame->linesize[0];
566 uint8_t *dst = frame->data[0];
569 while (bytestream2_get_bytes_left(gb) > 0) {
570 int count = bytestream2_get_byte(gb);
571 int pixel = bytestream2_get_byte(gb);
583 dst[pos + y * l] = pixel;
599 static int decode_frame(AVCodecContext *avctx, AVFrame *rframe,
600 int *got_frame, AVPacket *avpkt)
602 ArgoContext *s = avctx->priv_data;
603 GetByteContext *gb = &s->gb;
604 AVFrame *frame = s->frame;
609 return AVERROR_INVALIDDATA;
611 bytestream2_init(gb, avpkt->data, avpkt->size);
613 if ((ret = ff_reget_buffer(avctx, frame, 0)) < 0)
616 chunk = bytestream2_get_be32(gb);
618 case MKBETAG('P', 'A', 'L', '8'):
619 for (int y = 0; y < frame->height; y++)
620 memset(frame->data[0] + y * frame->linesize[0], 0, frame->width * s->bpp);
621 if (avctx->pix_fmt == AV_PIX_FMT_PAL8)
622 memset(frame->data[1], 0, AVPALETTE_SIZE);
623 return decode_pal8(avctx, s->pal);
624 case MKBETAG('M', 'A', 'D', '1'):
625 if (avctx->pix_fmt == AV_PIX_FMT_PAL8)
626 ret = decode_mad1(avctx, frame);
628 ret = decode_mad1_24(avctx, frame);
630 case MKBETAG('A', 'V', 'C', 'F'):
631 if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
633 ret = decode_avcf(avctx, frame);
636 case MKBETAG('A', 'L', 'C', 'D'):
637 if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
639 ret = decode_alcd(avctx, frame);
642 case MKBETAG('R', 'L', 'E', 'F'):
643 if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
645 ret = decode_rle(avctx, frame);
648 case MKBETAG('R', 'L', 'E', 'D'):
649 if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
651 ret = decode_rle(avctx, frame);
655 av_log(avctx, AV_LOG_DEBUG, "unknown chunk 0x%X\n", chunk);
662 if (avctx->pix_fmt == AV_PIX_FMT_PAL8)
663 memcpy(frame->data[1], s->pal, AVPALETTE_SIZE);
665 if ((ret = av_frame_ref(rframe, s->frame)) < 0)
668 frame->pict_type = s->key ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
670 frame->flags |= AV_FRAME_FLAG_KEY;
672 frame->flags &= ~AV_FRAME_FLAG_KEY;
678 static av_cold int decode_init(AVCodecContext *avctx)
680 ArgoContext *s = avctx->priv_data;
682 switch (avctx->bits_per_coded_sample) {
684 avctx->pix_fmt = AV_PIX_FMT_PAL8; break;
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;
691 if (avctx->width % 2 || avctx->height % 2) {
692 avpriv_request_sample(s, "Odd dimensions\n");
693 return AVERROR_PATCHWELCOME;
696 s->frame = av_frame_alloc();
698 return AVERROR(ENOMEM);
700 for (int n = 0, i = -4; i < 4; i++) {
701 for (int j = -14; j < 2; j++) {
707 for (int n = 0, i = -5; i <= 1; i += 2) {
720 static void decode_flush(AVCodecContext *avctx)
722 ArgoContext *s = avctx->priv_data;
724 av_frame_unref(s->frame);
727 static av_cold int decode_close(AVCodecContext *avctx)
729 ArgoContext *s = avctx->priv_data;
731 av_frame_free(&s->frame);
736 const FFCodec ff_argo_decoder = {
738 CODEC_LONG_NAME("Argonaut Games Video"),
739 .p.type = AVMEDIA_TYPE_VIDEO,
740 .p.id = AV_CODEC_ID_ARGO,
741 .priv_data_size = sizeof(ArgoContext),
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_CLEANUP,