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