745 lines · 23.7 KB · C
RawDownload
/* * Argonaut Games Video decoder * Copyright (c) 2020 Paul B Mahol * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include <string.h> #include "libavutil/internal.h"#include "libavutil/intreadwrite.h" #include "avcodec.h"#include "bytestream.h"#include "codec_internal.h"#include "decode.h" typedef struct ArgoContext {    GetByteContext gb;     int bpp;    int key;    int mv0[128][2];    int mv1[16][2];    uint32_t pal[256];    AVFrame *frame;} ArgoContext; static int decode_pal8(AVCodecContext *avctx, uint32_t *pal){    ArgoContext *s = avctx->priv_data;    GetByteContext *gb = &s->gb;    int start, count;     start = bytestream2_get_le16(gb);    count = bytestream2_get_le16(gb);     if (start + count > 256)        return AVERROR_INVALIDDATA;     if (bytestream2_get_bytes_left(gb) < 3 * count)        return AVERROR_INVALIDDATA;     for (int i = 0; i < count; i++)        pal[start + i] = (0xFFU << 24) | bytestream2_get_be24u(gb);     return 0;} static int decode_avcf(AVCodecContext *avctx, AVFrame *frame){    ArgoContext *s = avctx->priv_data;    GetByteContext *gb = &s->gb;    const int l = frame->linesize[0];    const uint8_t *map = gb->buffer;    uint8_t *dst = frame->data[0];     if (bytestream2_get_bytes_left(gb) < 1024 + (frame->width / 2) * (frame->height / 2))        return AVERROR_INVALIDDATA;     bytestream2_skipu(gb, 1024);    for (int y = 0; y < frame->height; y += 2) {        for (int x = 0; x < frame->width; x += 2) {            int index = bytestream2_get_byteu(gb);            const uint8_t *block = map + index * 4;             dst[x+0]   = block[0];            dst[x+1]   = block[1];            dst[x+l]   = block[2];            dst[x+l+1] = block[3];        }         dst += frame->linesize[0] * 2;    }     return 0;} static int decode_alcd(AVCodecContext *avctx, AVFrame *frame){    ArgoContext *s = avctx->priv_data;    GetByteContext *gb = &s->gb;    GetByteContext sb;    const int l = frame->linesize[0];    const uint8_t *map = gb->buffer;    uint8_t *dst = frame->data[0];    uint8_t codes = 0;    int count = 0;     if (bytestream2_get_bytes_left(gb) < 1024 + (((frame->width / 2) * (frame->height / 2) + 7) >> 3))        return AVERROR_INVALIDDATA;     bytestream2_skipu(gb, 1024);    sb = *gb;    bytestream2_skipu(gb, ((frame->width / 2) * (frame->height / 2) + 7) >> 3);     for (int y = 0; y < frame->height; y += 2) {        for (int x = 0; x < frame->width; x += 2) {            const uint8_t *block;            int index;             if (count == 0) {                codes = bytestream2_get_byteu(&sb);                count = 8;            }             if (codes & 0x80) {                index = bytestream2_get_byte(gb);                block = map + index * 4;                 dst[x+0]   = block[0];                dst[x+1]   = block[1];                dst[x+l]   = block[2];                dst[x+l+1] = block[3];            }             codes <<= 1;            count--;        }         dst += frame->linesize[0] * 2;    }     return 0;} static int decode_mad1(AVCodecContext *avctx, AVFrame *frame){    ArgoContext *s = avctx->priv_data;    GetByteContext *gb = &s->gb;    const int w = frame->width;    const int h = frame->height;    const int l = frame->linesize[0];     while (bytestream2_get_bytes_left(gb) > 0) {        int size, type, pos, dy;        uint8_t *dst;         type = bytestream2_get_byte(gb);        if (type == 0xFF)            break;         switch (type) {        case 8:            dst = frame->data[0];            for (int y = 0; y < h; y += 8) {                for (int x = 0; x < w; x += 8) {                    int fill = bytestream2_get_byte(gb);                    uint8_t *ddst = dst + x;                     for (int by = 0; by < 8; by++) {                        memset(ddst, fill, 8);                        ddst += l;                    }                }                 dst += 8 * l;            }            break;        case 7:            while (bytestream2_get_bytes_left(gb) > 0) {                int bsize = bytestream2_get_byte(gb);                uint8_t *src;                int count;                 if (!bsize)                    break;                 count = bytestream2_get_be16(gb);                while (count > 0) {                    int mvx, mvy, a, b, c, mx, my;                    int bsize_w, bsize_h;                     bsize_w = bsize_h = bsize;                    if (bytestream2_get_bytes_left(gb) < 4)                        return AVERROR_INVALIDDATA;                    mvx = bytestream2_get_byte(gb) * bsize;                    mvy = bytestream2_get_byte(gb) * bsize;                    a = bytestream2_get_byte(gb);                    b = bytestream2_get_byte(gb);                    c = ((a & 0x3F) << 8) + b;                    mx = mvx + (c  & 0x7F) - 64;                    my = mvy + (c >>    7) - 64;                     if (mvy < 0 || mvy >= h)                        return AVERROR_INVALIDDATA;                     if (mvx < 0 || mvx >= w)                        return AVERROR_INVALIDDATA;                     if (my < 0 || my >= h)                        return AVERROR_INVALIDDATA;                     if (mx < 0 || mx >= w)                        return AVERROR_INVALIDDATA;                     dst = frame->data[0] + mvx + l * mvy;                    src = frame->data[0] + mx  + l * my;                     bsize_w = FFMIN3(bsize_w, w - mvx, w - mx);                    bsize_h = FFMIN3(bsize_h, h - mvy, h - my);                     if (mvy >= my && (mvy != my || mvx >= mx)) {                        src += (bsize_h - 1) * l;                        dst += (bsize_h - 1) * l;                        for (int by = 0; by < bsize_h; by++) {                            memmove(dst, src, bsize_w);                            src -= l;                            dst -= l;                        }                    } else {                        for (int by = 0; by < bsize_h; by++) {                            memmove(dst, src, bsize_w);                            src += l;                            dst += l;                        }                    }                     count--;                }            }            break;        case 6:            dst = frame->data[0];            if (bytestream2_get_bytes_left(gb) < w * h)                return AVERROR_INVALIDDATA;            for (int y = 0; y < h; y++) {                bytestream2_get_bufferu(gb, dst, w);                dst += l;            }            break;        case 5:            dst = frame->data[0];            for (int y = 0; y < h; y += 2) {                for (int x = 0; x < w; x += 2) {                    int fill = bytestream2_get_byte(gb);                    uint8_t *ddst = dst + x;                     fill = (fill << 8) | fill;                    for (int by = 0; by < 2; by++) {                            AV_WN16(ddst, fill);                         ddst += l;                    }                }                 dst += 2 * l;            }            break;        case 3:            size = bytestream2_get_le16(gb);            if (size > 0) {                int x = bytestream2_get_byte(gb) * 4;                int y = bytestream2_get_byte(gb) * 4;                int count = bytestream2_get_byte(gb);                int fill = bytestream2_get_byte(gb);                 av_log(avctx, AV_LOG_DEBUG, "%d %d %d %d\n", x, y, count, fill);                for (int i = 0; i < count; i++)                    ;                return AVERROR_PATCHWELCOME;            }            break;        case 2:            dst = frame->data[0];            pos = 0;            dy  = 0;            while (bytestream2_get_bytes_left(gb) > 0) {                int count = bytestream2_get_byteu(gb);                int skip = count & 0x3F;                 count = count >> 6;                if (skip == 0x3F) {                    pos += 0x3E;                    while (pos >= w) {                        pos -= w;                        dst += l;                        dy++;                        if (dy >= h)                            return 0;                    }                } else {                    pos += skip;                    while (pos >= w) {                        pos -= w;                        dst += l;                        dy++;                        if (dy >= h)                            return 0;                    }                    while (count >= 0) {                        int bits = bytestream2_get_byte(gb);                         for (int i = 0; i < 4; i++) {                            switch (bits & 3) {                            case 0:                                break;                            case 1:                                if (dy < 1 && !pos)                                    return AVERROR_INVALIDDATA;                                else                                    dst[pos] = pos ? dst[pos - 1] : dst[-l + w - 1];                                break;                            case 2:                                if (dy < 1)                                    return AVERROR_INVALIDDATA;                                dst[pos] = dst[pos - l];                                break;                            case 3:                                dst[pos] = bytestream2_get_byte(gb);                                break;                            }                             pos++;                            if (pos >= w) {                                pos -= w;                                dst += l;                                dy++;                                if (dy >= h)                                    return 0;                            }                            bits >>= 2;                        }                        count--;                    }                }            }            break;        default:            return AVERROR_INVALIDDATA;        }    }     return 0;} static int decode_mad1_24(AVCodecContext *avctx, AVFrame *frame){    ArgoContext *s = avctx->priv_data;    GetByteContext *gb = &s->gb;    const int w = frame->width;    const int h = frame->height;    const int l = frame->linesize[0] / 4;     while (bytestream2_get_bytes_left(gb) > 0) {        int osize, type, pos, dy, di, bcode, value, v14;        const uint8_t *bits;        uint32_t *dst;         type = bytestream2_get_byte(gb);        if (type == 0xFF)            return 0;         switch (type) {        case 8:            dst = (uint32_t *)frame->data[0];            for (int y = 0; y + 12 <= h; y += 12) {                for (int x = 0; x + 12 <= w; x += 12) {                    int fill = bytestream2_get_be24(gb);                    uint32_t *dstp = dst + x;                     for (int by = 0; by < 12; by++) {                        for (int bx = 0; bx < 12; bx++)                            dstp[bx] = fill;                         dstp += l;                    }                }                 dst += 12 * l;            }            break;        case 7:            while (bytestream2_get_bytes_left(gb) > 0) {                int bsize = bytestream2_get_byte(gb);                uint32_t *src;                int count;                 if (!bsize)                    break;                 count = bytestream2_get_be16(gb);                while (count > 0) {                    int mvx, mvy, a, b, c, mx, my;                    int bsize_w, bsize_h;                     bsize_w = bsize_h = bsize;                    if (bytestream2_get_bytes_left(gb) < 4)                        return AVERROR_INVALIDDATA;                    mvx = bytestream2_get_byte(gb) * bsize;                    mvy = bytestream2_get_byte(gb) * bsize;                    a = bytestream2_get_byte(gb);                    b = bytestream2_get_byte(gb);                    c = ((a & 0x3F) << 8) + b;                    mx = mvx + (c  & 0x7F) - 64;                    my = mvy + (c >>    7) - 64;                     if (mvy < 0 || mvy >= h)                        return AVERROR_INVALIDDATA;                     if (mvx < 0 || mvx >= w)                        return AVERROR_INVALIDDATA;                     if (my < 0 || my >= h)                        return AVERROR_INVALIDDATA;                     if (mx < 0 || mx >= w)                        return AVERROR_INVALIDDATA;                     dst = (uint32_t *)frame->data[0] + mvx + l * mvy;                    src = (uint32_t *)frame->data[0] + mx  + l * my;                     bsize_w = FFMIN3(bsize_w, w - mvx, w - mx);                    bsize_h = FFMIN3(bsize_h, h - mvy, h - my);                     if (mvy >= my && (mvy != my || mvx >= mx)) {                        src += (bsize_h - 1) * l;                        dst += (bsize_h - 1) * l;                        for (int by = 0; by < bsize_h; by++) {                            memmove(dst, src, bsize_w * 4);                            src -= l;                            dst -= l;                        }                    } else {                        for (int by = 0; by < bsize_h; by++) {                            memmove(dst, src, bsize_w * 4);                            src += l;                            dst += l;                        }                    }                     count--;                }            }            break;        case 12:            osize = ((h + 3) / 4) * ((w + 3) / 4) + 7;            bits = gb->buffer;            di   = 0;            bcode = v14 = 0;            if (bytestream2_get_bytes_left(gb) < osize >> 3)                return AVERROR_INVALIDDATA;            bytestream2_skip(gb, osize >> 3);            for (int x = 0; x < w; x += 4) {                for (int y = 0; y < h; y += 4) {                    int astate = 0;                     if (bits[di >> 3] & (1 << (di & 7))) {                        int codes = bytestream2_get_byte(gb);                         for (int count = 0; count < 4; count++) {                            uint32_t *src = (uint32_t *)frame->data[0];                            size_t src_size = l * (h - 1) + (w - 1);                            int nv, v, code = codes & 3;                             pos = x;                            dy  = y + count;                            dst = (uint32_t *)frame->data[0] + pos + dy * l;                            if (code & 1)                                bcode = bytestream2_get_byte(gb);                            if (code == 3) {                                for (int j = 0; j < 4; j++) {                                    switch (bcode & 3) {                                    case 0:                                        break;                                    case 1:                                        if (dy < 1 && !pos)                                            return AVERROR_INVALIDDATA;                                        dst[0] = dst[-1];                                        break;                                    case 2:                                        if (dy < 1)                                            return AVERROR_INVALIDDATA;                                        dst[0] = dst[-l];                                        break;                                    case 3:                                        if (astate) {                                            nv = value >> 4;                                        } else {                                            value = bytestream2_get_byte(gb);                                            nv = value & 0xF;                                        }                                        astate ^= 1;                                        dst[0] = src[av_clip(l * (dy + s->mv1[nv][1]) + pos +                                                             s->mv1[nv][0], 0, src_size)];                                        break;

Lines 1–500 of 745.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t