Coverage Report

Created: 2025-12-31 07:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavcodec/sga.c
Line
Count
Source
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 "libavutil/mem.h"
23
#include "avcodec.h"
24
#include "get_bits.h"
25
#include "bytestream.h"
26
#include "codec_internal.h"
27
#include "decode.h"
28
29
213k
#define PALDATA_FOLLOWS_TILEDATA 4
30
#define HAVE_COMPRESSED_TILEMAP 32
31
652k
#define HAVE_TILEMAP 128
32
33
typedef struct SGAVideoContext {
34
    GetByteContext gb;
35
36
    int metadata_size;
37
    int tiledata_size;
38
    int tiledata_offset;
39
    int tilemapdata_size;
40
    int tilemapdata_offset;
41
    int paldata_size;
42
    int paldata_offset;
43
    int palmapdata_offset;
44
    int palmapdata_size;
45
46
    int flags;
47
    int nb_pal;
48
    int nb_tiles;
49
    int tiles_w, tiles_h;
50
    int shift;
51
    int plus;
52
    int swap;
53
54
    uint32_t pal[256];
55
    uint8_t *tileindex_data;
56
    unsigned tileindex_size;
57
    uint8_t *palmapindex_data;
58
    unsigned palmapindex_size;
59
    uint8_t uncompressed[65536];
60
} SGAVideoContext;
61
62
static av_cold int sga_decode_init(AVCodecContext *avctx)
63
1.73k
{
64
1.73k
    avctx->pix_fmt = AV_PIX_FMT_PAL8;
65
1.73k
    return 0;
66
1.73k
}
67
68
static int decode_palette(GetByteContext *gb, uint32_t *pal)
69
6.22k
{
70
6.22k
    GetBitContext gbit;
71
72
6.22k
    if (bytestream2_get_bytes_left(gb) < 18)
73
1.21k
        return AVERROR_INVALIDDATA;
74
75
5.01k
    memset(pal, 0, 16 * sizeof(*pal));
76
5.01k
    (void)init_get_bits8(&gbit, gb->buffer, 18);
77
78
20.0k
    for (int RGBIndex = 0; RGBIndex < 3; RGBIndex++) {
79
255k
        for (int index = 0; index < 16; index++) {
80
240k
            unsigned color = get_bits1(&gbit) << RGBIndex;
81
240k
            pal[15 - index] |= color << (5 + 16);
82
240k
        }
83
15.0k
    }
84
85
20.0k
    for (int RGBIndex = 0; RGBIndex < 3; RGBIndex++) {
86
255k
        for (int index = 0; index < 16; index++) {
87
240k
            unsigned color = get_bits1(&gbit) << RGBIndex;
88
240k
            pal[15 - index] |= color << (5 + 8);
89
240k
        }
90
15.0k
    }
91
92
20.0k
    for (int RGBIndex = 0; RGBIndex < 3; RGBIndex++) {
93
255k
        for (int index = 0; index < 16; index++) {
94
240k
            unsigned color = get_bits1(&gbit) << RGBIndex;
95
240k
            pal[15 - index] |= color << (5 + 0);
96
240k
        }
97
15.0k
    }
98
99
85.2k
    for (int index = 0; index < 16; index++)
100
80.2k
        pal[index] = (0xFFU << 24) | pal[index] | (pal[index] >> 3);
101
102
5.01k
    bytestream2_skip(gb, 18);
103
104
5.01k
    return 0;
105
6.22k
}
106
107
static int decode_index_palmap(SGAVideoContext *s, AVFrame *frame)
108
455
{
109
455
    const uint8_t *tt = s->tileindex_data;
110
111
6.06k
    for (int y = 0; y < s->tiles_h; y++) {
112
146k
        for (int x = 0; x < s->tiles_w; x++) {
113
140k
            int pal_idx = s->palmapindex_data[y * s->tiles_w + x] * 16;
114
140k
            uint8_t *dst = frame->data[0] + y * 8 * frame->linesize[0] + x * 8;
115
116
1.26M
            for (int yy = 0; yy < 8; yy++) {
117
10.1M
                for (int xx = 0; xx < 8; xx++)
118
8.98M
                    dst[xx] = pal_idx + tt[xx];
119
1.12M
                tt += 8;
120
121
1.12M
                dst += frame->linesize[0];
122
1.12M
            }
123
140k
        }
124
5.60k
    }
125
126
455
    return 0;
127
455
}
128
129
static int decode_index_tilemap(SGAVideoContext *s, AVFrame *frame)
130
721
{
131
721
    GetByteContext *gb = &s->gb, gb2;
132
133
721
    bytestream2_seek(gb, s->tilemapdata_offset, SEEK_SET);
134
721
    if (bytestream2_get_bytes_left(gb) < s->tilemapdata_size)
135
395
        return AVERROR_INVALIDDATA;
136
137
326
    gb2 = *gb;
138
139
6.09k
    for (int y = 0; y < s->tiles_h; y++) {
140
416k
        for (int x = 0; x < s->tiles_w; x++) {
141
410k
            uint8_t tile[64];
142
410k
            int tilemap = bytestream2_get_be16u(&gb2);
143
410k
            int flip_x = (tilemap >> 11) & 1;
144
410k
            int flip_y = (tilemap >> 12) & 1;
145
410k
            int tindex = av_clip((tilemap & 511) - 1, 0, s->nb_tiles - 1);
146
410k
            const uint8_t *tt = s->tileindex_data + tindex * 64;
147
410k
            int pal_idx = ((tilemap >> 13) & 3) * 16;
148
410k
            uint8_t *dst = frame->data[0] + y * 8 * frame->linesize[0] + x * 8;
149
150
410k
            if (!flip_x && !flip_y) {
151
286k
                memcpy(tile, tt, 64);
152
286k
            } else if (flip_x && flip_y) {
153
712k
                for (int i = 0; i < 8; i++) {
154
5.69M
                    for (int j = 0; j < 8; j++)
155
5.06M
                        tile[i * 8 + j] = tt[(7 - i) * 8 + 7 - j];
156
632k
                }
157
79.1k
            } else if (flip_x) {
158
226k
                for (int i = 0; i < 8; i++) {
159
1.81M
                    for (int j = 0; j < 8; j++)
160
1.61M
                        tile[i * 8 + j] = tt[i * 8 + 7 - j];
161
201k
                }
162
25.1k
            } else {
163
178k
                for (int i = 0; i < 8; i++) {
164
1.42M
                    for (int j = 0; j < 8; j++)
165
1.26M
                        tile[i * 8 + j] = tt[(7 - i) * 8 + j];
166
158k
                }
167
19.8k
            }
168
169
3.69M
            for (int yy = 0; yy < 8; yy++) {
170
29.5M
                for (int xx = 0; xx < 8; xx++)
171
26.2M
                    dst[xx] = pal_idx + tile[xx + yy * 8];
172
173
3.28M
                dst += frame->linesize[0];
174
3.28M
            }
175
410k
        }
176
5.77k
    }
177
178
326
    return 0;
179
721
}
180
181
static int decode_index(SGAVideoContext *s, AVFrame *frame)
182
323
{
183
323
    const uint8_t *src = s->tileindex_data;
184
323
    uint8_t *dst = frame->data[0];
185
186
4.51k
    for (int y = 0; y < frame->height; y += 8) {
187
55.4k
        for (int x = 0; x < frame->width; x += 8) {
188
461k
            for (int yy = 0; yy < 8; yy++) {
189
3.69M
                for (int xx = 0; xx < 8; xx++)
190
3.28M
                    dst[x + xx + yy * frame->linesize[0]] = src[xx];
191
410k
                src += 8;
192
410k
            }
193
51.2k
        }
194
195
4.18k
        dst += 8 * frame->linesize[0];
196
4.18k
    }
197
198
323
    return 0;
199
323
}
200
201
static int lzss_decompress(AVCodecContext *avctx,
202
                           GetByteContext *gb, uint8_t *dst,
203
                           int dst_size, int shift, int plus)
204
12.8k
{
205
12.8k
    int oi = 0;
206
207
92.6k
    while (bytestream2_get_bytes_left(gb) > 0 && oi < dst_size) {
208
91.0k
        uint16_t displace, header = bytestream2_get_be16(gb);
209
91.0k
        int count, offset;
210
211
1.45M
        for (int i = 0; i < 16; i++) {
212
1.37M
            switch (header >> 15) {
213
735k
            case 0:
214
735k
                if (oi + 2 < dst_size) {
215
725k
                    dst[oi++] = bytestream2_get_byte(gb);
216
725k
                    dst[oi++] = bytestream2_get_byte(gb);
217
725k
                }
218
735k
                break;
219
640k
            case 1:
220
640k
                displace = bytestream2_get_be16(gb);
221
640k
                count = displace >> shift;
222
640k
                offset = displace & ((1 << shift) - 1);
223
224
640k
                if (displace == 0) {
225
3.20M
                    while (bytestream2_get_bytes_left(gb) > 0 &&
226
3.19M
                           oi < dst_size)
227
3.19M
                        dst[oi++] = bytestream2_get_byte(gb);
228
10.2k
                    return oi;
229
10.2k
                }
230
231
630k
                count += plus;
232
233
630k
                if (offset <= 0)
234
1.62k
                    offset = 1;
235
630k
                if (oi < offset || oi + count * 2 > dst_size)
236
1.01k
                    return AVERROR_INVALIDDATA;
237
18.3M
                for (int j = 0; j < count * 2; j++) {
238
17.7M
                    dst[oi] = dst[oi - offset];
239
17.7M
                    oi++;
240
17.7M
                }
241
629k
                break;
242
1.37M
            }
243
244
1.36M
            header <<= 1;
245
1.36M
        }
246
91.0k
    }
247
248
1.62k
    return AVERROR_INVALIDDATA;
249
12.8k
}
250
251
static int decode_palmapdata(AVCodecContext *avctx)
252
735
{
253
735
    SGAVideoContext *s = avctx->priv_data;
254
735
    const int bits = (s->nb_pal + 1) / 2;
255
735
    GetByteContext *gb = &s->gb;
256
735
    GetBitContext pm;
257
735
    av_unused int ret;
258
259
735
    bytestream2_seek(gb, s->palmapdata_offset, SEEK_SET);
260
735
    if (bytestream2_get_bytes_left(gb) < s->palmapdata_size)
261
280
        return AVERROR_INVALIDDATA;
262
455
    ret = init_get_bits8(&pm, gb->buffer, s->palmapdata_size);
263
455
    av_assert1(ret >= 0);
264
265
6.06k
    for (int y = 0; y < s->tiles_h; y++) {
266
5.60k
        uint8_t *dst = s->palmapindex_data + y * s->tiles_w;
267
268
146k
        for (int x = 0; x < s->tiles_w; x++)
269
140k
            dst[x] = get_bits(&pm, bits);
270
271
5.60k
        dst += s->tiles_w;
272
5.60k
    }
273
274
455
    return 0;
275
735
}
276
277
static int decode_tiledata(AVCodecContext *avctx)
278
4.27k
{
279
4.27k
    SGAVideoContext *s = avctx->priv_data;
280
4.27k
    GetByteContext *gb = &s->gb;
281
4.27k
    GetBitContext tm;
282
4.27k
    av_unused int ret;
283
284
4.27k
    bytestream2_seek(gb, s->tiledata_offset, SEEK_SET);
285
4.27k
    if (bytestream2_get_bytes_left(gb) < s->tiledata_size)
286
2.49k
        return AVERROR_INVALIDDATA;
287
1.77k
    ret = init_get_bits8(&tm, gb->buffer, s->tiledata_size);
288
1.77k
    av_assert1(ret >= 0);
289
290
385k
    for (int n = 0; n < s->nb_tiles; n++) {
291
383k
        uint8_t *dst = s->tileindex_data + n * 64;
292
293
3.45M
        for (int yy = 0; yy < 8; yy++) {
294
27.6M
            for (int xx = 0; xx < 8; xx++)
295
24.5M
                dst[xx] = get_bits(&tm, 4);
296
297
3.07M
            dst += 8;
298
3.07M
        }
299
383k
    }
300
301
77.2k
    for (int i = 0; i < s->nb_tiles && s->swap; i++) {
302
75.4k
        uint8_t *dst = s->tileindex_data + i * 64;
303
304
377k
        for (int j = 8; j < 64; j += 16) {
305
1.50M
            for (int k = 0; k < 8; k += 2)
306
1.20M
                FFSWAP(uint8_t, dst[j + k], dst[j+k+1]);
307
301k
        }
308
75.4k
    }
309
310
1.77k
    return 0;
311
4.27k
}
312
313
static int sga_decode_frame(AVCodecContext *avctx, AVFrame *frame,
314
                            int *got_frame, AVPacket *avpkt)
315
143k
{
316
143k
    SGAVideoContext *s = avctx->priv_data;
317
143k
    GetByteContext *gb = &s->gb;
318
143k
    int ret, type;
319
320
143k
    if (avpkt->size <= 14)
321
24.5k
        return AVERROR_INVALIDDATA;
322
323
119k
    s->flags  = avpkt->data[8];
324
119k
    s->nb_pal = avpkt->data[9];
325
119k
    s->tiles_w = avpkt->data[10];
326
119k
    s->tiles_h = avpkt->data[11];
327
328
119k
    if (s->nb_pal > 4)
329
4.86k
        return AVERROR_INVALIDDATA;
330
331
114k
    if ((ret = ff_set_dimensions(avctx,
332
114k
                                 s->tiles_w * 8,
333
114k
                                 s->tiles_h * 8)) < 0)
334
1.27k
        return ret;
335
336
113k
    av_fast_padded_malloc(&s->tileindex_data, &s->tileindex_size,
337
113k
                          avctx->width * avctx->height);
338
113k
    if (!s->tileindex_data)
339
0
        return AVERROR(ENOMEM);
340
341
113k
    av_fast_padded_malloc(&s->palmapindex_data, &s->palmapindex_size,
342
113k
                          s->tiles_w * s->tiles_h);
343
113k
    if (!s->palmapindex_data)
344
0
        return AVERROR(ENOMEM);
345
346
113k
    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
347
0
        return ret;
348
349
113k
    bytestream2_init(gb, avpkt->data, avpkt->size);
350
351
113k
    type = bytestream2_get_byte(gb);
352
113k
    s->metadata_size = 12 + ((!!(s->flags & HAVE_TILEMAP)) * 2);
353
113k
    s->nb_tiles = s->flags & HAVE_TILEMAP ? AV_RB16(avpkt->data + 12) : s->tiles_w * s->tiles_h;
354
113k
    if (s->nb_tiles > s->tiles_w * s->tiles_h)
355
647
        return AVERROR_INVALIDDATA;
356
357
112k
    av_log(avctx, AV_LOG_DEBUG, "type: %X flags: %X nb_tiles: %d\n", type, s->flags, s->nb_tiles);
358
359
112k
    switch (type) {
360
4.46k
    case 0xE7:
361
5.37k
    case 0xCB:
362
6.67k
    case 0xCD:
363
6.67k
        s->swap = 1;
364
6.67k
        s->shift = 12;
365
6.67k
        s->plus = 1;
366
6.67k
        break;
367
555
    case 0xC9:
368
555
        s->swap = 1;
369
555
        s->shift = 13;
370
555
        s->plus = 1;
371
555
        break;
372
621
    case 0xC8:
373
621
        s->swap = 1;
374
621
        s->shift = 13;
375
621
        s->plus = 0;
376
621
        break;
377
241
    case 0xC7:
378
241
        s->swap = 0;
379
241
        s->shift = 13;
380
241
        s->plus = 1;
381
241
        break;
382
3.19k
    case 0xC6:
383
3.19k
        s->swap = 0;
384
3.19k
        s->shift = 13;
385
3.19k
        s->plus = 0;
386
3.19k
        break;
387
112k
    }
388
389
112k
    if (type == 0xE7) {
390
4.46k
        int offset = s->metadata_size, left;
391
4.46k
        int sizes[3];
392
393
4.46k
        bytestream2_seek(gb, s->metadata_size, SEEK_SET);
394
395
17.8k
        for (int i = 0; i < 3; i++)
396
13.3k
            sizes[i] = bytestream2_get_be16(gb);
397
398
11.5k
        for (int i = 0; i < 3; i++) {
399
9.43k
            int size = sizes[i];
400
9.43k
            int raw = size >> 15;
401
402
9.43k
            size &= (1 << 15) - 1;
403
404
9.43k
            if (raw) {
405
2.54k
                if (bytestream2_get_bytes_left(gb) < size)
406
425
                    return AVERROR_INVALIDDATA;
407
408
2.11k
                if (sizeof(s->uncompressed) - offset < size)
409
34
                    return AVERROR_INVALIDDATA;
410
411
2.08k
                memcpy(s->uncompressed + offset, gb->buffer, size);
412
2.08k
                bytestream2_skip(gb, size);
413
6.89k
            } else {
414
6.89k
                GetByteContext gb2;
415
416
6.89k
                if (bytestream2_get_bytes_left(gb) < size)
417
823
                    return AVERROR_INVALIDDATA;
418
419
6.07k
                bytestream2_init(&gb2, gb->buffer, size);
420
6.07k
                ret = lzss_decompress(avctx, &gb2, s->uncompressed + offset,
421
6.07k
                                      sizeof(s->uncompressed) - offset, s->shift, s->plus);
422
6.07k
                if (ret < 0)
423
1.11k
                    return ret;
424
4.95k
                bytestream2_skip(gb, size);
425
4.95k
                size = ret;
426
4.95k
            }
427
428
7.03k
            offset += size;
429
7.03k
        }
430
431
2.06k
        left = bytestream2_get_bytes_left(gb);
432
2.06k
        if (sizeof(s->uncompressed) - offset < left)
433
49
            return AVERROR_INVALIDDATA;
434
435
2.01k
        bytestream2_get_buffer(gb, s->uncompressed + offset, left);
436
437
2.01k
        offset += left;
438
2.01k
        bytestream2_init(gb, s->uncompressed, offset);
439
2.01k
    }
440
441
110k
    switch (type) {
442
1.29k
    case 0xCD:
443
2.21k
    case 0xCB:
444
2.77k
    case 0xC9:
445
3.39k
    case 0xC8:
446
3.63k
    case 0xC7:
447
6.82k
    case 0xC6:
448
6.82k
        bytestream2_seek(gb, s->metadata_size, SEEK_SET);
449
6.82k
        ret = lzss_decompress(avctx, gb, s->uncompressed + s->metadata_size,
450
6.82k
                              sizeof(s->uncompressed) - s->metadata_size, s->shift, s->plus);
451
6.82k
        if (ret < 0)
452
1.52k
            return ret;
453
5.29k
        bytestream2_init(gb, s->uncompressed, ret + s->metadata_size);
454
7.31k
    case 0xE7:
455
106k
    case 0xC1:
456
106k
        s->tiledata_size = s->nb_tiles * 32;
457
106k
        s->paldata_size = s->nb_pal * 18;
458
106k
        s->tiledata_offset = s->flags & PALDATA_FOLLOWS_TILEDATA ? s->metadata_size : s->metadata_size + s->paldata_size;
459
106k
        s->paldata_offset = s->flags & PALDATA_FOLLOWS_TILEDATA ? s->metadata_size + s->tiledata_size : s->metadata_size;
460
106k
        s->palmapdata_offset = (s->flags & HAVE_TILEMAP) ? -1 : s->paldata_offset + s->paldata_size;
461
106k
        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;
462
106k
        s->tilemapdata_size = (s->flags & HAVE_TILEMAP) ? s->tiles_w * s->tiles_h * 2 : 0;
463
106k
        s->tilemapdata_offset = (s->flags & HAVE_TILEMAP) ? s->paldata_offset + s->paldata_size: -1;
464
465
106k
        bytestream2_seek(gb, s->paldata_offset, SEEK_SET);
466
111k
        for (int n = 0; n < s->nb_pal; n++) {
467
6.22k
            ret = decode_palette(gb, s->pal + 16 * n);
468
6.22k
            if (ret < 0)
469
1.21k
                return ret;
470
6.22k
        }
471
472
105k
        if (s->tiledata_size > 0) {
473
4.27k
            ret = decode_tiledata(avctx);
474
4.27k
            if (ret < 0)
475
2.49k
                return ret;
476
4.27k
        }
477
478
102k
        if (s->palmapdata_size > 0) {
479
735
            ret = decode_palmapdata(avctx);
480
735
            if (ret < 0)
481
280
                return ret;
482
735
        }
483
484
102k
        if (s->palmapdata_size > 0 && s->tiledata_size > 0) {
485
455
            ret = decode_index_palmap(s, frame);
486
455
            if (ret < 0)
487
0
                return ret;
488
102k
        } else if (s->tilemapdata_size > 0 && s->tiledata_size > 0) {
489
721
            ret = decode_index_tilemap(s, frame);
490
721
            if (ret < 0)
491
395
                return ret;
492
101k
        } else if (s->tiledata_size > 0) {
493
323
            ret = decode_index(s, frame);
494
323
            if (ret < 0)
495
0
                return ret;
496
323
        }
497
102k
        break;
498
102k
    default:
499
1.95k
        av_log(avctx, AV_LOG_ERROR, "Unknown type: %X\n", type);
500
1.95k
        return AVERROR_INVALIDDATA;
501
110k
    }
502
503
102k
    memcpy(frame->data[1], s->pal, AVPALETTE_SIZE);
504
102k
    frame->pict_type = AV_PICTURE_TYPE_I;
505
102k
    frame->flags |= AV_FRAME_FLAG_KEY;
506
507
102k
    *got_frame = 1;
508
509
102k
    return avpkt->size;
510
110k
}
511
512
static av_cold int sga_decode_end(AVCodecContext *avctx)
513
1.73k
{
514
1.73k
    SGAVideoContext *s = avctx->priv_data;
515
516
1.73k
    av_freep(&s->tileindex_data);
517
1.73k
    s->tileindex_size = 0;
518
519
1.73k
    av_freep(&s->palmapindex_data);
520
1.73k
    s->palmapindex_size = 0;
521
522
1.73k
    return 0;
523
1.73k
}
524
525
const FFCodec ff_sga_decoder = {
526
    .p.name         = "sga",
527
    CODEC_LONG_NAME("Digital Pictures SGA Video"),
528
    .p.type         = AVMEDIA_TYPE_VIDEO,
529
    .p.id           = AV_CODEC_ID_SGA_VIDEO,
530
    .priv_data_size = sizeof(SGAVideoContext),
531
    .init           = sga_decode_init,
532
    FF_CODEC_DECODE_CB(sga_decode_frame),
533
    .close          = sga_decode_end,
534
    .p.capabilities = AV_CODEC_CAP_DR1,
535
};