Coverage Report

Created: 2025-08-28 07:12

/src/ffmpeg/libavcodec/pictordec.c
Line
Count
Source
1
/*
2
 * Pictor/PC Paint decoder
3
 * Copyright (c) 2010 Peter Ross <pross@xvid.org>
4
 *
5
 * This file is part of FFmpeg.
6
 *
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.
11
 *
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.
16
 *
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
20
 */
21
22
/**
23
 * @file
24
 * Pictor/PC Paint decoder
25
 */
26
27
#include "libavutil/imgutils.h"
28
#include "libavutil/mem.h"
29
#include "avcodec.h"
30
#include "bytestream.h"
31
#include "cga_data.h"
32
#include "codec_internal.h"
33
#include "decode.h"
34
35
typedef struct PicContext {
36
    int width, height;
37
    int nb_planes;
38
    GetByteContext g;
39
} PicContext;
40
41
static void picmemset_8bpp(PicContext *s, AVFrame *frame, int value, int run,
42
                           int *x, int *y)
43
717k
{
44
2.53M
    while (run > 0) {
45
2.43M
        uint8_t *d = frame->data[0] + *y * frame->linesize[0];
46
2.43M
        if (*x + run >= s->width) {
47
1.81M
            int n = s->width - *x;
48
1.81M
            memset(d + *x, value, n);
49
1.81M
            run -= n;
50
1.81M
            *x = 0;
51
1.81M
            *y -= 1;
52
1.81M
            if (*y < 0)
53
464
                break;
54
1.81M
        } else {
55
621k
            memset(d + *x, value, run);
56
621k
            *x += run;
57
621k
            break;
58
621k
        }
59
2.43M
    }
60
717k
}
61
62
static void picmemset(PicContext *s, AVFrame *frame, unsigned value, int run,
63
                      int *x, int *y, int *plane, int bits_per_plane)
64
798k
{
65
798k
    uint8_t *d;
66
798k
    int shift = *plane * bits_per_plane;
67
798k
    unsigned mask  = ((1U << bits_per_plane) - 1) << shift;
68
798k
    int xl = *x;
69
798k
    int yl = *y;
70
798k
    int planel = *plane;
71
798k
    int pixels_per_value = 8/bits_per_plane;
72
798k
    value   <<= shift;
73
74
798k
    d = frame->data[0] + yl * frame->linesize[0];
75
13.2M
    while (run > 0) {
76
12.4M
        int j;
77
43.9M
        for (j = 8-bits_per_plane; j >= 0; j -= bits_per_plane) {
78
31.5M
            d[xl] |= (value >> j) & mask;
79
31.5M
            xl += 1;
80
40.0M
            while (xl == s->width) {
81
8.57M
                yl -= 1;
82
8.57M
                xl = 0;
83
8.57M
                if (yl < 0) {
84
3.36k
                   yl = s->height - 1;
85
3.36k
                   planel += 1;
86
3.36k
                   if (planel >= s->nb_planes)
87
1.02k
                       goto end;
88
2.34k
                   value <<= bits_per_plane;
89
2.34k
                   mask  <<= bits_per_plane;
90
2.34k
                }
91
8.57M
                d = frame->data[0] + yl * frame->linesize[0];
92
8.57M
                if (s->nb_planes == 1 &&
93
8.57M
                    run*pixels_per_value >= s->width &&
94
8.57M
                    pixels_per_value < (s->width / pixels_per_value * pixels_per_value)
95
8.57M
                    ) {
96
9.13M
                    for (; xl < pixels_per_value; xl ++) {
97
7.30M
                        j = (j < bits_per_plane ? 8 : j) - bits_per_plane;
98
7.30M
                        d[xl] |= (value >> j) & mask;
99
7.30M
                    }
100
1.83M
                    av_memcpy_backptr(d+xl, pixels_per_value, s->width - xl);
101
1.83M
                    run -= s->width / pixels_per_value;
102
1.83M
                    xl = s->width / pixels_per_value * pixels_per_value;
103
1.83M
                }
104
8.57M
            }
105
31.5M
        }
106
12.4M
        run--;
107
12.4M
    }
108
798k
end:
109
798k
    *x = xl;
110
798k
    *y = yl;
111
798k
    *plane = planel;
112
798k
}
113
114
static const uint8_t cga_mode45_index[6][4] = {
115
    [0] = { 0, 3,  5,   7 }, // mode4, palette#1, low intensity
116
    [1] = { 0, 2,  4,   6 }, // mode4, palette#2, low intensity
117
    [2] = { 0, 3,  4,   7 }, // mode5, low intensity
118
    [3] = { 0, 11, 13, 15 }, // mode4, palette#1, high intensity
119
    [4] = { 0, 10, 12, 14 }, // mode4, palette#2, high intensity
120
    [5] = { 0, 11, 12, 15 }, // mode5, high intensity
121
};
122
123
static int decode_frame(AVCodecContext *avctx, AVFrame *frame,
124
                        int *got_frame, AVPacket *avpkt)
125
311k
{
126
311k
    PicContext *s = avctx->priv_data;
127
311k
    uint32_t *palette;
128
311k
    int bits_per_plane, bpp, etype, esize, npal, pos_after_pal;
129
311k
    int i, x, y, plane, tmp, ret, val;
130
131
311k
    bytestream2_init(&s->g, avpkt->data, avpkt->size);
132
133
311k
    if (bytestream2_get_bytes_left(&s->g) < 11)
134
171k
        return AVERROR_INVALIDDATA;
135
136
139k
    if (bytestream2_get_le16u(&s->g) != 0x1234)
137
9.64k
        return AVERROR_INVALIDDATA;
138
139
130k
    s->width       = bytestream2_get_le16u(&s->g);
140
130k
    s->height      = bytestream2_get_le16u(&s->g);
141
130k
    bytestream2_skip(&s->g, 4);
142
130k
    tmp            = bytestream2_get_byteu(&s->g);
143
130k
    bits_per_plane = tmp & 0xF;
144
130k
    s->nb_planes   = (tmp >> 4) + 1;
145
130k
    bpp            = bits_per_plane * s->nb_planes;
146
130k
    if (bits_per_plane > 8 || bpp < 1 || bpp > 32) {
147
1.13k
        avpriv_request_sample(avctx, "Unsupported bit depth");
148
1.13k
        return AVERROR_PATCHWELCOME;
149
1.13k
    }
150
151
128k
    if (bytestream2_peek_byte(&s->g) == 0xFF || bpp == 1 || bpp == 4 || bpp == 8) {
152
120k
        bytestream2_skip(&s->g, 2);
153
120k
        etype = bytestream2_get_le16(&s->g);
154
120k
        esize = bytestream2_get_le16(&s->g);
155
120k
        if (bytestream2_get_bytes_left(&s->g) < esize)
156
744
            return AVERROR_INVALIDDATA;
157
120k
    } else {
158
8.33k
        etype = -1;
159
8.33k
        esize = 0;
160
8.33k
    }
161
162
128k
    avctx->pix_fmt = AV_PIX_FMT_PAL8;
163
164
128k
    if (av_image_check_size(s->width, s->height, 0, avctx) < 0)
165
924
        return -1;
166
167
    /*
168
        There are 2 coding modes, RLE and RAW.
169
        Undamaged RAW should be proportional to W*H and thus bigger than RLE
170
        RLE codes the most compressed runs by
171
        1 byte for val (=marker)
172
        1 byte run (=0)
173
        2 bytes run
174
        1 byte val
175
        that's 5 bytes and the maximum run we can code is 65535
176
177
        The RLE decoder can exit prematurly but it does not on any image available
178
        Based on this the formula is assumed correct for undamaged images.
179
        If an image is found which exploits the special end
180
        handling and breaks this formula then this needs to be adapted.
181
    */
182
127k
    if (bytestream2_get_bytes_left(&s->g) < s->width * s->height / 65535 * 5)
183
10.8k
        return AVERROR_INVALIDDATA;
184
185
116k
    if (s->width != avctx->width || s->height != avctx->height) {
186
5.66k
        ret = ff_set_dimensions(avctx, s->width, s->height);
187
5.66k
        if (ret < 0)
188
194
            return ret;
189
5.66k
    }
190
191
116k
    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
192
194
        return ret;
193
116k
    memset(frame->data[0], 0, s->height * frame->linesize[0]);
194
116k
    frame->pict_type           = AV_PICTURE_TYPE_I;
195
196
116k
    pos_after_pal = bytestream2_tell(&s->g) + esize;
197
116k
    palette = (uint32_t*)frame->data[1];
198
116k
    if (etype == 1 && esize > 1 && bytestream2_peek_byte(&s->g) < 6) {
199
650
        int idx = bytestream2_get_byte(&s->g);
200
650
        npal = 4;
201
3.25k
        for (i = 0; i < npal; i++)
202
2.60k
            palette[i] = ff_cga_palette[ cga_mode45_index[idx][i] ];
203
115k
    } else if (etype == 2) {
204
681
        npal = FFMIN(esize, 16);
205
5.20k
        for (i = 0; i < npal; i++) {
206
4.52k
            int pal_idx = bytestream2_get_byte(&s->g);
207
4.52k
            palette[i]  = ff_cga_palette[FFMIN(pal_idx, 15)];
208
4.52k
        }
209
114k
    } else if (etype == 3) {
210
806
        npal = FFMIN(esize, 16);
211
6.49k
        for (i = 0; i < npal; i++) {
212
5.68k
            int pal_idx = bytestream2_get_byte(&s->g);
213
5.68k
            palette[i]  = ff_ega_palette[FFMIN(pal_idx, 63)];
214
5.68k
        }
215
113k
    } else if (etype == 4 || etype == 5) {
216
894
        npal = FFMIN(esize / 3, 256);
217
57.7k
        for (i = 0; i < npal; i++) {
218
56.8k
            palette[i] = bytestream2_get_be24(&s->g) << 2;
219
56.8k
            palette[i] |= 0xFFU << 24 | palette[i] >> 6 & 0x30303;
220
56.8k
        }
221
113k
    } else {
222
113k
        if (bpp == 1) {
223
945
            npal = 2;
224
945
            palette[0] = 0xFF000000;
225
945
            palette[1] = 0xFFFFFFFF;
226
112k
        } else if (bpp == 2) {
227
2.02k
            npal = 4;
228
10.1k
            for (i = 0; i < npal; i++)
229
8.08k
                palette[i] = ff_cga_palette[ cga_mode45_index[0][i] ];
230
110k
        } else {
231
110k
            npal = 16;
232
110k
            memcpy(palette, ff_cga_palette, npal * 4);
233
110k
        }
234
113k
    }
235
    // fill remaining palette entries
236
116k
    memset(palette + npal, 0, AVPALETTE_SIZE - npal * 4);
237
    // skip remaining palette bytes
238
116k
    bytestream2_seek(&s->g, pos_after_pal, SEEK_SET);
239
240
116k
    val = 0;
241
116k
    y = s->height - 1;
242
116k
    if (bytestream2_get_le16(&s->g)) {
243
2.70k
        x = 0;
244
2.70k
        plane = 0;
245
1.68M
        while (bytestream2_get_bytes_left(&s->g) >= 6) {
246
1.67M
            int stop_size, marker, t1, t2;
247
248
1.67M
            t1        = bytestream2_get_bytes_left(&s->g);
249
1.67M
            t2        = bytestream2_get_le16(&s->g);
250
1.67M
            stop_size = t1 - FFMIN(t1, t2);
251
            // ignore uncompressed block size
252
1.67M
            bytestream2_skip(&s->g, 2);
253
1.67M
            marker    = bytestream2_get_byte(&s->g);
254
255
3.19M
            while (plane < s->nb_planes &&
256
3.19M
                   bytestream2_get_bytes_left(&s->g) > stop_size) {
257
1.51M
                int run = 1;
258
1.51M
                val = bytestream2_get_byte(&s->g);
259
1.51M
                if (val == marker) {
260
169k
                    run = bytestream2_get_byte(&s->g);
261
169k
                    if (run == 0)
262
154k
                        run = bytestream2_get_le16(&s->g);
263
169k
                    val = bytestream2_get_byte(&s->g);
264
169k
                }
265
266
1.51M
                if (bits_per_plane == 8) {
267
717k
                    picmemset_8bpp(s, frame, val, run, &x, &y);
268
717k
                    if (y < 0)
269
230
                        goto finish;
270
797k
                } else {
271
797k
                    picmemset(s, frame, val, run, &x, &y, &plane, bits_per_plane);
272
797k
                }
273
1.51M
            }
274
1.67M
        }
275
276
2.47k
        if (s->nb_planes - plane > 1)
277
819
            return AVERROR_INVALIDDATA;
278
279
1.65k
        if (plane < s->nb_planes && x < avctx->width) {
280
1.27k
            int run = (y + 1) * avctx->width - x;
281
1.27k
            if (bits_per_plane == 8)
282
234
                picmemset_8bpp(s, frame, val, run, &x, &y);
283
1.03k
            else
284
1.03k
                picmemset(s, frame, val, run / (8 / bits_per_plane), &x, &y, &plane, bits_per_plane);
285
1.27k
        }
286
113k
    } else {
287
378k
        while (y >= 0 && bytestream2_get_bytes_left(&s->g) > 0) {
288
264k
            memcpy(frame->data[0] + y * frame->linesize[0], s->g.buffer, FFMIN(avctx->width, bytestream2_get_bytes_left(&s->g)));
289
264k
            bytestream2_skip(&s->g, avctx->width);
290
264k
            y--;
291
264k
        }
292
113k
    }
293
115k
finish:
294
295
115k
    *got_frame      = 1;
296
115k
    return avpkt->size;
297
116k
}
298
299
const FFCodec ff_pictor_decoder = {
300
    .p.name         = "pictor",
301
    CODEC_LONG_NAME("Pictor/PC Paint"),
302
    .p.type         = AVMEDIA_TYPE_VIDEO,
303
    .p.id           = AV_CODEC_ID_PICTOR,
304
    .p.capabilities = AV_CODEC_CAP_DR1,
305
    .priv_data_size = sizeof(PicContext),
306
    FF_CODEC_DECODE_CB(decode_frame),
307
};