xref: /third_party/ffmpeg/libavcodec/sga.c (revision cabdff1a)
1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * Copyright (c) 2021 Paul B Mahol
3cabdff1aSopenharmony_ci *
4cabdff1aSopenharmony_ci * This file is part of FFmpeg.
5cabdff1aSopenharmony_ci *
6cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
7cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
8cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
9cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
10cabdff1aSopenharmony_ci *
11cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
12cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
13cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14cabdff1aSopenharmony_ci * Lesser General Public License for more details.
15cabdff1aSopenharmony_ci *
16cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
17cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
18cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19cabdff1aSopenharmony_ci */
20cabdff1aSopenharmony_ci
21cabdff1aSopenharmony_ci#include "libavutil/common.h"
22cabdff1aSopenharmony_ci#include "avcodec.h"
23cabdff1aSopenharmony_ci#include "get_bits.h"
24cabdff1aSopenharmony_ci#include "bytestream.h"
25cabdff1aSopenharmony_ci#include "codec_internal.h"
26cabdff1aSopenharmony_ci#include "internal.h"
27cabdff1aSopenharmony_ci
28cabdff1aSopenharmony_ci#define PALDATA_FOLLOWS_TILEDATA 4
29cabdff1aSopenharmony_ci#define HAVE_COMPRESSED_TILEMAP 32
30cabdff1aSopenharmony_ci#define HAVE_TILEMAP 128
31cabdff1aSopenharmony_ci
32cabdff1aSopenharmony_citypedef struct SGAVideoContext {
33cabdff1aSopenharmony_ci    GetByteContext gb;
34cabdff1aSopenharmony_ci
35cabdff1aSopenharmony_ci    int metadata_size;
36cabdff1aSopenharmony_ci    int tiledata_size;
37cabdff1aSopenharmony_ci    int tiledata_offset;
38cabdff1aSopenharmony_ci    int tilemapdata_size;
39cabdff1aSopenharmony_ci    int tilemapdata_offset;
40cabdff1aSopenharmony_ci    int paldata_size;
41cabdff1aSopenharmony_ci    int paldata_offset;
42cabdff1aSopenharmony_ci    int palmapdata_offset;
43cabdff1aSopenharmony_ci    int palmapdata_size;
44cabdff1aSopenharmony_ci
45cabdff1aSopenharmony_ci    int flags;
46cabdff1aSopenharmony_ci    int nb_pal;
47cabdff1aSopenharmony_ci    int nb_tiles;
48cabdff1aSopenharmony_ci    int tiles_w, tiles_h;
49cabdff1aSopenharmony_ci    int shift;
50cabdff1aSopenharmony_ci    int plus;
51cabdff1aSopenharmony_ci    int swap;
52cabdff1aSopenharmony_ci
53cabdff1aSopenharmony_ci    uint32_t pal[256];
54cabdff1aSopenharmony_ci    uint8_t *tileindex_data;
55cabdff1aSopenharmony_ci    unsigned tileindex_size;
56cabdff1aSopenharmony_ci    uint8_t *palmapindex_data;
57cabdff1aSopenharmony_ci    unsigned palmapindex_size;
58cabdff1aSopenharmony_ci    uint8_t uncompressed[65536];
59cabdff1aSopenharmony_ci} SGAVideoContext;
60cabdff1aSopenharmony_ci
61cabdff1aSopenharmony_cistatic av_cold int sga_decode_init(AVCodecContext *avctx)
62cabdff1aSopenharmony_ci{
63cabdff1aSopenharmony_ci    avctx->pix_fmt = AV_PIX_FMT_PAL8;
64cabdff1aSopenharmony_ci    return 0;
65cabdff1aSopenharmony_ci}
66cabdff1aSopenharmony_ci
67cabdff1aSopenharmony_cistatic int decode_palette(GetByteContext *gb, uint32_t *pal)
68cabdff1aSopenharmony_ci{
69cabdff1aSopenharmony_ci    GetBitContext gbit;
70cabdff1aSopenharmony_ci
71cabdff1aSopenharmony_ci    if (bytestream2_get_bytes_left(gb) < 18)
72cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
73cabdff1aSopenharmony_ci
74cabdff1aSopenharmony_ci    memset(pal, 0, 16 * sizeof(*pal));
75cabdff1aSopenharmony_ci    init_get_bits8(&gbit, gb->buffer, 18);
76cabdff1aSopenharmony_ci
77cabdff1aSopenharmony_ci    for (int RGBIndex = 0; RGBIndex < 3; RGBIndex++) {
78cabdff1aSopenharmony_ci        for (int index = 0; index < 16; index++) {
79cabdff1aSopenharmony_ci            unsigned color = get_bits1(&gbit) << RGBIndex;
80cabdff1aSopenharmony_ci            pal[15 - index] |= color << (5 + 16);
81cabdff1aSopenharmony_ci        }
82cabdff1aSopenharmony_ci    }
83cabdff1aSopenharmony_ci
84cabdff1aSopenharmony_ci    for (int RGBIndex = 0; RGBIndex < 3; RGBIndex++) {
85cabdff1aSopenharmony_ci        for (int index = 0; index < 16; index++) {
86cabdff1aSopenharmony_ci            unsigned color = get_bits1(&gbit) << RGBIndex;
87cabdff1aSopenharmony_ci            pal[15 - index] |= color << (5 + 8);
88cabdff1aSopenharmony_ci        }
89cabdff1aSopenharmony_ci    }
90cabdff1aSopenharmony_ci
91cabdff1aSopenharmony_ci    for (int RGBIndex = 0; RGBIndex < 3; RGBIndex++) {
92cabdff1aSopenharmony_ci        for (int index = 0; index < 16; index++) {
93cabdff1aSopenharmony_ci            unsigned color = get_bits1(&gbit) << RGBIndex;
94cabdff1aSopenharmony_ci            pal[15 - index] |= color << (5 + 0);
95cabdff1aSopenharmony_ci        }
96cabdff1aSopenharmony_ci    }
97cabdff1aSopenharmony_ci
98cabdff1aSopenharmony_ci    for (int index = 0; index < 16; index++)
99cabdff1aSopenharmony_ci        pal[index] = (0xFFU << 24) | pal[index] | (pal[index] >> 3);
100cabdff1aSopenharmony_ci
101cabdff1aSopenharmony_ci    bytestream2_skip(gb, 18);
102cabdff1aSopenharmony_ci
103cabdff1aSopenharmony_ci    return 0;
104cabdff1aSopenharmony_ci}
105cabdff1aSopenharmony_ci
106cabdff1aSopenharmony_cistatic int decode_index_palmap(SGAVideoContext *s, AVFrame *frame)
107cabdff1aSopenharmony_ci{
108cabdff1aSopenharmony_ci    const uint8_t *tt = s->tileindex_data;
109cabdff1aSopenharmony_ci
110cabdff1aSopenharmony_ci    for (int y = 0; y < s->tiles_h; y++) {
111cabdff1aSopenharmony_ci        for (int x = 0; x < s->tiles_w; x++) {
112cabdff1aSopenharmony_ci            int pal_idx = s->palmapindex_data[y * s->tiles_w + x] * 16;
113cabdff1aSopenharmony_ci            uint8_t *dst = frame->data[0] + y * 8 * frame->linesize[0] + x * 8;
114cabdff1aSopenharmony_ci
115cabdff1aSopenharmony_ci            for (int yy = 0; yy < 8; yy++) {
116cabdff1aSopenharmony_ci                for (int xx = 0; xx < 8; xx++)
117cabdff1aSopenharmony_ci                    dst[xx] = pal_idx + tt[xx];
118cabdff1aSopenharmony_ci                tt += 8;
119cabdff1aSopenharmony_ci
120cabdff1aSopenharmony_ci                dst += frame->linesize[0];
121cabdff1aSopenharmony_ci            }
122cabdff1aSopenharmony_ci        }
123cabdff1aSopenharmony_ci    }
124cabdff1aSopenharmony_ci
125cabdff1aSopenharmony_ci    return 0;
126cabdff1aSopenharmony_ci}
127cabdff1aSopenharmony_ci
128cabdff1aSopenharmony_cistatic int decode_index_tilemap(SGAVideoContext *s, AVFrame *frame)
129cabdff1aSopenharmony_ci{
130cabdff1aSopenharmony_ci    GetByteContext *gb = &s->gb;
131cabdff1aSopenharmony_ci    GetBitContext pm;
132cabdff1aSopenharmony_ci
133cabdff1aSopenharmony_ci    bytestream2_seek(gb, s->tilemapdata_offset, SEEK_SET);
134cabdff1aSopenharmony_ci    if (bytestream2_get_bytes_left(gb) < s->tilemapdata_size)
135cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
136cabdff1aSopenharmony_ci
137cabdff1aSopenharmony_ci    init_get_bits8(&pm, gb->buffer, s->tilemapdata_size);
138cabdff1aSopenharmony_ci
139cabdff1aSopenharmony_ci    for (int y = 0; y < s->tiles_h; y++) {
140cabdff1aSopenharmony_ci        for (int x = 0; x < s->tiles_w; x++) {
141cabdff1aSopenharmony_ci            uint8_t tile[64];
142cabdff1aSopenharmony_ci            int tilemap = get_bits(&pm, 16);
143cabdff1aSopenharmony_ci            int flip_x = (tilemap >> 11) & 1;
144cabdff1aSopenharmony_ci            int flip_y = (tilemap >> 12) & 1;
145cabdff1aSopenharmony_ci            int tindex = av_clip((tilemap & 511) - 1, 0, s->nb_tiles - 1);
146cabdff1aSopenharmony_ci            const uint8_t *tt = s->tileindex_data + tindex * 64;
147cabdff1aSopenharmony_ci            int pal_idx = ((tilemap >> 13) & 3) * 16;
148cabdff1aSopenharmony_ci            uint8_t *dst = frame->data[0] + y * 8 * frame->linesize[0] + x * 8;
149cabdff1aSopenharmony_ci
150cabdff1aSopenharmony_ci            if (!flip_x && !flip_y) {
151cabdff1aSopenharmony_ci                memcpy(tile, tt, 64);
152cabdff1aSopenharmony_ci            } else if (flip_x && flip_y) {
153cabdff1aSopenharmony_ci                for (int i = 0; i < 8; i++) {
154cabdff1aSopenharmony_ci                    for (int j = 0; j < 8; j++)
155cabdff1aSopenharmony_ci                        tile[i * 8 + j] = tt[(7 - i) * 8 + 7 - j];
156cabdff1aSopenharmony_ci                }
157cabdff1aSopenharmony_ci            } else if (flip_x) {
158cabdff1aSopenharmony_ci                for (int i = 0; i < 8; i++) {
159cabdff1aSopenharmony_ci                    for (int j = 0; j < 8; j++)
160cabdff1aSopenharmony_ci                        tile[i * 8 + j] = tt[i * 8 + 7 - j];
161cabdff1aSopenharmony_ci                }
162cabdff1aSopenharmony_ci            } else {
163cabdff1aSopenharmony_ci                for (int i = 0; i < 8; i++) {
164cabdff1aSopenharmony_ci                    for (int j = 0; j < 8; j++)
165cabdff1aSopenharmony_ci                        tile[i * 8 + j] = tt[(7 - i) * 8 + j];
166cabdff1aSopenharmony_ci                }
167cabdff1aSopenharmony_ci            }
168cabdff1aSopenharmony_ci
169cabdff1aSopenharmony_ci            for (int yy = 0; yy < 8; yy++) {
170cabdff1aSopenharmony_ci                for (int xx = 0; xx < 8; xx++)
171cabdff1aSopenharmony_ci                    dst[xx] = pal_idx + tile[xx + yy * 8];
172cabdff1aSopenharmony_ci
173cabdff1aSopenharmony_ci                dst += frame->linesize[0];
174cabdff1aSopenharmony_ci            }
175cabdff1aSopenharmony_ci        }
176cabdff1aSopenharmony_ci    }
177cabdff1aSopenharmony_ci
178cabdff1aSopenharmony_ci    return 0;
179cabdff1aSopenharmony_ci}
180cabdff1aSopenharmony_ci
181cabdff1aSopenharmony_cistatic int decode_index(SGAVideoContext *s, AVFrame *frame)
182cabdff1aSopenharmony_ci{
183cabdff1aSopenharmony_ci    const uint8_t *src = s->tileindex_data;
184cabdff1aSopenharmony_ci    uint8_t *dst = frame->data[0];
185cabdff1aSopenharmony_ci
186cabdff1aSopenharmony_ci    for (int y = 0; y < frame->height; y += 8) {
187cabdff1aSopenharmony_ci        for (int x = 0; x < frame->width; x += 8) {
188cabdff1aSopenharmony_ci            for (int yy = 0; yy < 8; yy++) {
189cabdff1aSopenharmony_ci                for (int xx = 0; xx < 8; xx++)
190cabdff1aSopenharmony_ci                    dst[x + xx + yy * frame->linesize[0]] = src[xx];
191cabdff1aSopenharmony_ci                src += 8;
192cabdff1aSopenharmony_ci            }
193cabdff1aSopenharmony_ci        }
194cabdff1aSopenharmony_ci
195cabdff1aSopenharmony_ci        dst += 8 * frame->linesize[0];
196cabdff1aSopenharmony_ci    }
197cabdff1aSopenharmony_ci
198cabdff1aSopenharmony_ci    return 0;
199cabdff1aSopenharmony_ci}
200cabdff1aSopenharmony_ci
201cabdff1aSopenharmony_cistatic int lzss_decompress(AVCodecContext *avctx,
202cabdff1aSopenharmony_ci                           GetByteContext *gb, uint8_t *dst,
203cabdff1aSopenharmony_ci                           int dst_size, int shift, int plus)
204cabdff1aSopenharmony_ci{
205cabdff1aSopenharmony_ci    int oi = 0;
206cabdff1aSopenharmony_ci
207cabdff1aSopenharmony_ci    while (bytestream2_get_bytes_left(gb) > 0 && oi < dst_size) {
208cabdff1aSopenharmony_ci        uint16_t displace, header = bytestream2_get_be16(gb);
209cabdff1aSopenharmony_ci        int count, offset;
210cabdff1aSopenharmony_ci
211cabdff1aSopenharmony_ci        for (int i = 0; i < 16; i++) {
212cabdff1aSopenharmony_ci            switch (header >> 15) {
213cabdff1aSopenharmony_ci            case 0:
214cabdff1aSopenharmony_ci                if (oi + 2 < dst_size) {
215cabdff1aSopenharmony_ci                    dst[oi++] = bytestream2_get_byte(gb);
216cabdff1aSopenharmony_ci                    dst[oi++] = bytestream2_get_byte(gb);
217cabdff1aSopenharmony_ci                }
218cabdff1aSopenharmony_ci                break;
219cabdff1aSopenharmony_ci            case 1:
220cabdff1aSopenharmony_ci                displace = bytestream2_get_be16(gb);
221cabdff1aSopenharmony_ci                count = displace >> shift;
222cabdff1aSopenharmony_ci                offset = displace & ((1 << shift) - 1);
223cabdff1aSopenharmony_ci
224cabdff1aSopenharmony_ci                if (displace == 0) {
225cabdff1aSopenharmony_ci                    while (bytestream2_get_bytes_left(gb) > 0 &&
226cabdff1aSopenharmony_ci                           oi < dst_size)
227cabdff1aSopenharmony_ci                        dst[oi++] = bytestream2_get_byte(gb);
228cabdff1aSopenharmony_ci                    return oi;
229cabdff1aSopenharmony_ci                }
230cabdff1aSopenharmony_ci
231cabdff1aSopenharmony_ci                count += plus;
232cabdff1aSopenharmony_ci
233cabdff1aSopenharmony_ci                if (offset <= 0)
234cabdff1aSopenharmony_ci                    offset = 1;
235cabdff1aSopenharmony_ci                if (oi < offset || oi + count * 2 > dst_size)
236cabdff1aSopenharmony_ci                    return AVERROR_INVALIDDATA;
237cabdff1aSopenharmony_ci                for (int j = 0; j < count * 2; j++) {
238cabdff1aSopenharmony_ci                    dst[oi] = dst[oi - offset];
239cabdff1aSopenharmony_ci                    oi++;
240cabdff1aSopenharmony_ci                }
241cabdff1aSopenharmony_ci                break;
242cabdff1aSopenharmony_ci            }
243cabdff1aSopenharmony_ci
244cabdff1aSopenharmony_ci            header <<= 1;
245cabdff1aSopenharmony_ci        }
246cabdff1aSopenharmony_ci    }
247cabdff1aSopenharmony_ci
248cabdff1aSopenharmony_ci    return AVERROR_INVALIDDATA;
249cabdff1aSopenharmony_ci}
250cabdff1aSopenharmony_ci
251cabdff1aSopenharmony_cistatic int decode_palmapdata(AVCodecContext *avctx)
252cabdff1aSopenharmony_ci{
253cabdff1aSopenharmony_ci    SGAVideoContext *s = avctx->priv_data;
254cabdff1aSopenharmony_ci    const int bits = (s->nb_pal + 1) / 2;
255cabdff1aSopenharmony_ci    GetByteContext *gb = &s->gb;
256cabdff1aSopenharmony_ci    GetBitContext pm;
257cabdff1aSopenharmony_ci
258cabdff1aSopenharmony_ci    bytestream2_seek(gb, s->palmapdata_offset, SEEK_SET);
259cabdff1aSopenharmony_ci    if (bytestream2_get_bytes_left(gb) < s->palmapdata_size)
260cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
261cabdff1aSopenharmony_ci    init_get_bits8(&pm, gb->buffer, s->palmapdata_size);
262cabdff1aSopenharmony_ci
263cabdff1aSopenharmony_ci    for (int y = 0; y < s->tiles_h; y++) {
264cabdff1aSopenharmony_ci        uint8_t *dst = s->palmapindex_data + y * s->tiles_w;
265cabdff1aSopenharmony_ci
266cabdff1aSopenharmony_ci        for (int x = 0; x < s->tiles_w; x++)
267cabdff1aSopenharmony_ci            dst[x] = get_bits(&pm, bits);
268cabdff1aSopenharmony_ci
269cabdff1aSopenharmony_ci        dst += s->tiles_w;
270cabdff1aSopenharmony_ci    }
271cabdff1aSopenharmony_ci
272cabdff1aSopenharmony_ci    return 0;
273cabdff1aSopenharmony_ci}
274cabdff1aSopenharmony_ci
275cabdff1aSopenharmony_cistatic int decode_tiledata(AVCodecContext *avctx)
276cabdff1aSopenharmony_ci{
277cabdff1aSopenharmony_ci    SGAVideoContext *s = avctx->priv_data;
278cabdff1aSopenharmony_ci    GetByteContext *gb = &s->gb;
279cabdff1aSopenharmony_ci    GetBitContext tm;
280cabdff1aSopenharmony_ci
281cabdff1aSopenharmony_ci    bytestream2_seek(gb, s->tiledata_offset, SEEK_SET);
282cabdff1aSopenharmony_ci    if (bytestream2_get_bytes_left(gb) < s->tiledata_size)
283cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
284cabdff1aSopenharmony_ci    init_get_bits8(&tm, gb->buffer, s->tiledata_size);
285cabdff1aSopenharmony_ci
286cabdff1aSopenharmony_ci    for (int n = 0; n < s->nb_tiles; n++) {
287cabdff1aSopenharmony_ci        uint8_t *dst = s->tileindex_data + n * 64;
288cabdff1aSopenharmony_ci
289cabdff1aSopenharmony_ci        for (int yy = 0; yy < 8; yy++) {
290cabdff1aSopenharmony_ci            for (int xx = 0; xx < 8; xx++)
291cabdff1aSopenharmony_ci                dst[xx] = get_bits(&tm, 4);
292cabdff1aSopenharmony_ci
293cabdff1aSopenharmony_ci            dst += 8;
294cabdff1aSopenharmony_ci        }
295cabdff1aSopenharmony_ci    }
296cabdff1aSopenharmony_ci
297cabdff1aSopenharmony_ci    for (int i = 0; i < s->nb_tiles && s->swap; i++) {
298cabdff1aSopenharmony_ci        uint8_t *dst = s->tileindex_data + i * 64;
299cabdff1aSopenharmony_ci
300cabdff1aSopenharmony_ci        for (int j = 8; j < 64; j += 16) {
301cabdff1aSopenharmony_ci            for (int k = 0; k < 8; k += 2)
302cabdff1aSopenharmony_ci                FFSWAP(uint8_t, dst[j + k], dst[j+k+1]);
303cabdff1aSopenharmony_ci        }
304cabdff1aSopenharmony_ci    }
305cabdff1aSopenharmony_ci
306cabdff1aSopenharmony_ci    return 0;
307cabdff1aSopenharmony_ci}
308cabdff1aSopenharmony_ci
309cabdff1aSopenharmony_cistatic int sga_decode_frame(AVCodecContext *avctx, AVFrame *frame,
310cabdff1aSopenharmony_ci                            int *got_frame, AVPacket *avpkt)
311cabdff1aSopenharmony_ci{
312cabdff1aSopenharmony_ci    SGAVideoContext *s = avctx->priv_data;
313cabdff1aSopenharmony_ci    GetByteContext *gb = &s->gb;
314cabdff1aSopenharmony_ci    int ret, type;
315cabdff1aSopenharmony_ci
316cabdff1aSopenharmony_ci    if (avpkt->size <= 14)
317cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
318cabdff1aSopenharmony_ci
319cabdff1aSopenharmony_ci    s->flags  = avpkt->data[8];
320cabdff1aSopenharmony_ci    s->nb_pal = avpkt->data[9];
321cabdff1aSopenharmony_ci    s->tiles_w = avpkt->data[10];
322cabdff1aSopenharmony_ci    s->tiles_h = avpkt->data[11];
323cabdff1aSopenharmony_ci
324cabdff1aSopenharmony_ci    if (s->nb_pal > 4)
325cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
326cabdff1aSopenharmony_ci
327cabdff1aSopenharmony_ci    if ((ret = ff_set_dimensions(avctx,
328cabdff1aSopenharmony_ci                                 s->tiles_w * 8,
329cabdff1aSopenharmony_ci                                 s->tiles_h * 8)) < 0)
330cabdff1aSopenharmony_ci        return ret;
331cabdff1aSopenharmony_ci
332cabdff1aSopenharmony_ci    av_fast_padded_malloc(&s->tileindex_data, &s->tileindex_size,
333cabdff1aSopenharmony_ci                          avctx->width * avctx->height);
334cabdff1aSopenharmony_ci    if (!s->tileindex_data)
335cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
336cabdff1aSopenharmony_ci
337cabdff1aSopenharmony_ci    av_fast_padded_malloc(&s->palmapindex_data, &s->palmapindex_size,
338cabdff1aSopenharmony_ci                          s->tiles_w * s->tiles_h);
339cabdff1aSopenharmony_ci    if (!s->palmapindex_data)
340cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
341cabdff1aSopenharmony_ci
342cabdff1aSopenharmony_ci    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
343cabdff1aSopenharmony_ci        return ret;
344cabdff1aSopenharmony_ci
345cabdff1aSopenharmony_ci    bytestream2_init(gb, avpkt->data, avpkt->size);
346cabdff1aSopenharmony_ci
347cabdff1aSopenharmony_ci    type = bytestream2_get_byte(gb);
348cabdff1aSopenharmony_ci    s->metadata_size = 12 + ((!!(s->flags & HAVE_TILEMAP)) * 2);
349cabdff1aSopenharmony_ci    s->nb_tiles = s->flags & HAVE_TILEMAP ? AV_RB16(avpkt->data + 12) : s->tiles_w * s->tiles_h;
350cabdff1aSopenharmony_ci    if (s->nb_tiles > s->tiles_w * s->tiles_h)
351cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
352cabdff1aSopenharmony_ci
353cabdff1aSopenharmony_ci    av_log(avctx, AV_LOG_DEBUG, "type: %X flags: %X nb_tiles: %d\n", type, s->flags, s->nb_tiles);
354cabdff1aSopenharmony_ci
355cabdff1aSopenharmony_ci    switch (type) {
356cabdff1aSopenharmony_ci    case 0xE7:
357cabdff1aSopenharmony_ci    case 0xCB:
358cabdff1aSopenharmony_ci    case 0xCD:
359cabdff1aSopenharmony_ci        s->swap = 1;
360cabdff1aSopenharmony_ci        s->shift = 12;
361cabdff1aSopenharmony_ci        s->plus = 1;
362cabdff1aSopenharmony_ci        break;
363cabdff1aSopenharmony_ci    case 0xC9:
364cabdff1aSopenharmony_ci        s->swap = 1;
365cabdff1aSopenharmony_ci        s->shift = 13;
366cabdff1aSopenharmony_ci        s->plus = 1;
367cabdff1aSopenharmony_ci        break;
368cabdff1aSopenharmony_ci    case 0xC8:
369cabdff1aSopenharmony_ci        s->swap = 1;
370cabdff1aSopenharmony_ci        s->shift = 13;
371cabdff1aSopenharmony_ci        s->plus = 0;
372cabdff1aSopenharmony_ci        break;
373cabdff1aSopenharmony_ci    case 0xC7:
374cabdff1aSopenharmony_ci        s->swap = 0;
375cabdff1aSopenharmony_ci        s->shift = 13;
376cabdff1aSopenharmony_ci        s->plus = 1;
377cabdff1aSopenharmony_ci        break;
378cabdff1aSopenharmony_ci    case 0xC6:
379cabdff1aSopenharmony_ci        s->swap = 0;
380cabdff1aSopenharmony_ci        s->shift = 13;
381cabdff1aSopenharmony_ci        s->plus = 0;
382cabdff1aSopenharmony_ci        break;
383cabdff1aSopenharmony_ci    }
384cabdff1aSopenharmony_ci
385cabdff1aSopenharmony_ci    if (type == 0xE7) {
386cabdff1aSopenharmony_ci        int offset = s->metadata_size, left;
387cabdff1aSopenharmony_ci        int sizes[3];
388cabdff1aSopenharmony_ci
389cabdff1aSopenharmony_ci        bytestream2_seek(gb, s->metadata_size, SEEK_SET);
390cabdff1aSopenharmony_ci
391cabdff1aSopenharmony_ci        for (int i = 0; i < 3; i++)
392cabdff1aSopenharmony_ci            sizes[i] = bytestream2_get_be16(gb);
393cabdff1aSopenharmony_ci
394cabdff1aSopenharmony_ci        for (int i = 0; i < 3; i++) {
395cabdff1aSopenharmony_ci            int size = sizes[i];
396cabdff1aSopenharmony_ci            int raw = size >> 15;
397cabdff1aSopenharmony_ci
398cabdff1aSopenharmony_ci            size &= (1 << 15) - 1;
399cabdff1aSopenharmony_ci
400cabdff1aSopenharmony_ci            if (raw) {
401cabdff1aSopenharmony_ci                if (bytestream2_get_bytes_left(gb) < size)
402cabdff1aSopenharmony_ci                    return AVERROR_INVALIDDATA;
403cabdff1aSopenharmony_ci
404cabdff1aSopenharmony_ci                if (sizeof(s->uncompressed) - offset < size)
405cabdff1aSopenharmony_ci                    return AVERROR_INVALIDDATA;
406cabdff1aSopenharmony_ci
407cabdff1aSopenharmony_ci                memcpy(s->uncompressed + offset, gb->buffer, size);
408cabdff1aSopenharmony_ci                bytestream2_skip(gb, size);
409cabdff1aSopenharmony_ci            } else {
410cabdff1aSopenharmony_ci                GetByteContext gb2;
411cabdff1aSopenharmony_ci
412cabdff1aSopenharmony_ci                if (bytestream2_get_bytes_left(gb) < size)
413cabdff1aSopenharmony_ci                    return AVERROR_INVALIDDATA;
414cabdff1aSopenharmony_ci
415cabdff1aSopenharmony_ci                bytestream2_init(&gb2, gb->buffer, size);
416cabdff1aSopenharmony_ci                ret = lzss_decompress(avctx, &gb2, s->uncompressed + offset,
417cabdff1aSopenharmony_ci                                      sizeof(s->uncompressed) - offset, s->shift, s->plus);
418cabdff1aSopenharmony_ci                if (ret < 0)
419cabdff1aSopenharmony_ci                    return ret;
420cabdff1aSopenharmony_ci                bytestream2_skip(gb, size);
421cabdff1aSopenharmony_ci                size = ret;
422cabdff1aSopenharmony_ci            }
423cabdff1aSopenharmony_ci
424cabdff1aSopenharmony_ci            offset += size;
425cabdff1aSopenharmony_ci        }
426cabdff1aSopenharmony_ci
427cabdff1aSopenharmony_ci        left = bytestream2_get_bytes_left(gb);
428cabdff1aSopenharmony_ci        if (sizeof(s->uncompressed) - offset < left)
429cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
430cabdff1aSopenharmony_ci
431cabdff1aSopenharmony_ci        bytestream2_get_buffer(gb, s->uncompressed + offset, left);
432cabdff1aSopenharmony_ci
433cabdff1aSopenharmony_ci        offset += left;
434cabdff1aSopenharmony_ci        bytestream2_init(gb, s->uncompressed, offset);
435cabdff1aSopenharmony_ci    }
436cabdff1aSopenharmony_ci
437cabdff1aSopenharmony_ci    switch (type) {
438cabdff1aSopenharmony_ci    case 0xCD:
439cabdff1aSopenharmony_ci    case 0xCB:
440cabdff1aSopenharmony_ci    case 0xC9:
441cabdff1aSopenharmony_ci    case 0xC8:
442cabdff1aSopenharmony_ci    case 0xC7:
443cabdff1aSopenharmony_ci    case 0xC6:
444cabdff1aSopenharmony_ci        bytestream2_seek(gb, s->metadata_size, SEEK_SET);
445cabdff1aSopenharmony_ci        ret = lzss_decompress(avctx, gb, s->uncompressed + s->metadata_size,
446cabdff1aSopenharmony_ci                              sizeof(s->uncompressed) - s->metadata_size, s->shift, s->plus);
447cabdff1aSopenharmony_ci        if (ret < 0)
448cabdff1aSopenharmony_ci            return ret;
449cabdff1aSopenharmony_ci        bytestream2_init(gb, s->uncompressed, ret + s->metadata_size);
450cabdff1aSopenharmony_ci    case 0xE7:
451cabdff1aSopenharmony_ci    case 0xC1:
452cabdff1aSopenharmony_ci        s->tiledata_size = s->nb_tiles * 32;
453cabdff1aSopenharmony_ci        s->paldata_size = s->nb_pal * 18;
454cabdff1aSopenharmony_ci        s->tiledata_offset = s->flags & PALDATA_FOLLOWS_TILEDATA ? s->metadata_size : s->metadata_size + s->paldata_size;
455cabdff1aSopenharmony_ci        s->paldata_offset = s->flags & PALDATA_FOLLOWS_TILEDATA ? s->metadata_size + s->tiledata_size : s->metadata_size;
456cabdff1aSopenharmony_ci        s->palmapdata_offset = (s->flags & HAVE_TILEMAP) ? -1 : s->paldata_offset + s->paldata_size;
457cabdff1aSopenharmony_ci        s->palmapdata_size = (s->flags & HAVE_TILEMAP) || s->nb_pal < 2 ? 0 : (s->tiles_w * s->tiles_h * ((s->nb_pal + 1) / 2) + 7) / 8;
458cabdff1aSopenharmony_ci        s->tilemapdata_size = (s->flags & HAVE_TILEMAP) ? s->tiles_w * s->tiles_h * 2 : 0;
459cabdff1aSopenharmony_ci        s->tilemapdata_offset = (s->flags & HAVE_TILEMAP) ? s->paldata_offset + s->paldata_size: -1;
460cabdff1aSopenharmony_ci
461cabdff1aSopenharmony_ci        bytestream2_seek(gb, s->paldata_offset, SEEK_SET);
462cabdff1aSopenharmony_ci        for (int n = 0; n < s->nb_pal; n++) {
463cabdff1aSopenharmony_ci            ret = decode_palette(gb, s->pal + 16 * n);
464cabdff1aSopenharmony_ci            if (ret < 0)
465cabdff1aSopenharmony_ci                return ret;
466cabdff1aSopenharmony_ci        }
467cabdff1aSopenharmony_ci
468cabdff1aSopenharmony_ci        if (s->tiledata_size > 0) {
469cabdff1aSopenharmony_ci            ret = decode_tiledata(avctx);
470cabdff1aSopenharmony_ci            if (ret < 0)
471cabdff1aSopenharmony_ci                return ret;
472cabdff1aSopenharmony_ci        }
473cabdff1aSopenharmony_ci
474cabdff1aSopenharmony_ci        if (s->palmapdata_size > 0) {
475cabdff1aSopenharmony_ci            ret = decode_palmapdata(avctx);
476cabdff1aSopenharmony_ci            if (ret < 0)
477cabdff1aSopenharmony_ci                return ret;
478cabdff1aSopenharmony_ci        }
479cabdff1aSopenharmony_ci
480cabdff1aSopenharmony_ci        if (s->palmapdata_size > 0 && s->tiledata_size > 0) {
481cabdff1aSopenharmony_ci            ret = decode_index_palmap(s, frame);
482cabdff1aSopenharmony_ci            if (ret < 0)
483cabdff1aSopenharmony_ci                return ret;
484cabdff1aSopenharmony_ci        } else if (s->tilemapdata_size > 0 && s->tiledata_size > 0) {
485cabdff1aSopenharmony_ci            ret = decode_index_tilemap(s, frame);
486cabdff1aSopenharmony_ci            if (ret < 0)
487cabdff1aSopenharmony_ci                return ret;
488cabdff1aSopenharmony_ci        } else if (s->tiledata_size > 0) {
489cabdff1aSopenharmony_ci            ret = decode_index(s, frame);
490cabdff1aSopenharmony_ci            if (ret < 0)
491cabdff1aSopenharmony_ci                return ret;
492cabdff1aSopenharmony_ci        }
493cabdff1aSopenharmony_ci        break;
494cabdff1aSopenharmony_ci    default:
495cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Unknown type: %X\n", type);
496cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
497cabdff1aSopenharmony_ci    }
498cabdff1aSopenharmony_ci
499cabdff1aSopenharmony_ci    memcpy(frame->data[1], s->pal, AVPALETTE_SIZE);
500cabdff1aSopenharmony_ci    frame->palette_has_changed = 1;
501cabdff1aSopenharmony_ci    frame->pict_type = AV_PICTURE_TYPE_I;
502cabdff1aSopenharmony_ci    frame->key_frame = 1;
503cabdff1aSopenharmony_ci
504cabdff1aSopenharmony_ci    *got_frame = 1;
505cabdff1aSopenharmony_ci
506cabdff1aSopenharmony_ci    return avpkt->size;
507cabdff1aSopenharmony_ci}
508cabdff1aSopenharmony_ci
509cabdff1aSopenharmony_cistatic av_cold int sga_decode_end(AVCodecContext *avctx)
510cabdff1aSopenharmony_ci{
511cabdff1aSopenharmony_ci    SGAVideoContext *s = avctx->priv_data;
512cabdff1aSopenharmony_ci
513cabdff1aSopenharmony_ci    av_freep(&s->tileindex_data);
514cabdff1aSopenharmony_ci    s->tileindex_size = 0;
515cabdff1aSopenharmony_ci
516cabdff1aSopenharmony_ci    av_freep(&s->palmapindex_data);
517cabdff1aSopenharmony_ci    s->palmapindex_size = 0;
518cabdff1aSopenharmony_ci
519cabdff1aSopenharmony_ci    return 0;
520cabdff1aSopenharmony_ci}
521cabdff1aSopenharmony_ci
522cabdff1aSopenharmony_ciconst FFCodec ff_sga_decoder = {
523cabdff1aSopenharmony_ci    .p.name         = "sga",
524cabdff1aSopenharmony_ci    .p.long_name    = NULL_IF_CONFIG_SMALL("Digital Pictures SGA Video"),
525cabdff1aSopenharmony_ci    .p.type         = AVMEDIA_TYPE_VIDEO,
526cabdff1aSopenharmony_ci    .p.id           = AV_CODEC_ID_SGA_VIDEO,
527cabdff1aSopenharmony_ci    .priv_data_size = sizeof(SGAVideoContext),
528cabdff1aSopenharmony_ci    .init           = sga_decode_init,
529cabdff1aSopenharmony_ci    FF_CODEC_DECODE_CB(sga_decode_frame),
530cabdff1aSopenharmony_ci    .close          = sga_decode_end,
531cabdff1aSopenharmony_ci    .p.capabilities = AV_CODEC_CAP_DR1,
532cabdff1aSopenharmony_ci    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE,
533cabdff1aSopenharmony_ci};
534