GCC Code Coverage Report
Directory: ../../../ffmpeg/ Exec Total Coverage
File: src/libavcodec/pictordec.c Lines: 101 167 60.5 %
Date: 2019-11-18 18:00:01 Branches: 48 120 40.0 %

Line Branch Exec 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 "avcodec.h"
29
#include "bytestream.h"
30
#include "cga_data.h"
31
#include "internal.h"
32
33
typedef struct PicContext {
34
    int width, height;
35
    int nb_planes;
36
    GetByteContext g;
37
} PicContext;
38
39
static void picmemset_8bpp(PicContext *s, AVFrame *frame, int value, int run,
40
                           int *x, int *y)
41
{
42
    while (run > 0) {
43
        uint8_t *d = frame->data[0] + *y * frame->linesize[0];
44
        if (*x + run >= s->width) {
45
            int n = s->width - *x;
46
            memset(d + *x, value, n);
47
            run -= n;
48
            *x = 0;
49
            *y -= 1;
50
            if (*y < 0)
51
                break;
52
        } else {
53
            memset(d + *x, value, run);
54
            *x += run;
55
            break;
56
        }
57
    }
58
}
59
60
46974
static void picmemset(PicContext *s, AVFrame *frame, unsigned value, int run,
61
                      int *x, int *y, int *plane, int bits_per_plane)
62
{
63
    uint8_t *d;
64
46974
    int shift = *plane * bits_per_plane;
65
46974
    unsigned mask  = ((1U << bits_per_plane) - 1) << shift;
66
46974
    int xl = *x;
67
46974
    int yl = *y;
68
46974
    int planel = *plane;
69
46974
    int pixels_per_value = 8/bits_per_plane;
70
46974
    value   <<= shift;
71
72
46974
    d = frame->data[0] + yl * frame->linesize[0];
73
111244
    while (run > 0) {
74
        int j;
75
578446
        for (j = 8-bits_per_plane; j >= 0; j -= bits_per_plane) {
76
514176
            d[xl] |= (value >> j) & mask;
77
514176
            xl += 1;
78
515822
            while (xl == s->width) {
79
1648
                yl -= 1;
80
1648
                xl = 0;
81
1648
                if (yl < 0) {
82
8
                   yl = s->height - 1;
83
8
                   planel += 1;
84
8
                   if (planel >= s->nb_planes)
85
2
                       goto end;
86
6
                   value <<= bits_per_plane;
87
6
                   mask  <<= bits_per_plane;
88
                }
89
1646
                d = frame->data[0] + yl * frame->linesize[0];
90
1646
                if (s->nb_planes == 1 &&
91
                    run*pixels_per_value >= s->width &&
92
                    pixels_per_value < s->width &&
93
                    s->width % pixels_per_value == 0
94
                    ) {
95
                    for (; xl < pixels_per_value; xl ++) {
96
                        j = (j < bits_per_plane ? 8 : j) - bits_per_plane;
97
                        d[xl] |= (value >> j) & mask;
98
                    }
99
                    av_memcpy_backptr(d+xl, pixels_per_value, s->width - xl);
100
                    run -= s->width / pixels_per_value;
101
                    xl = s->width;
102
                }
103
            }
104
        }
105
64270
        run--;
106
    }
107
46972
end:
108
46974
    *x = xl;
109
46974
    *y = yl;
110
46974
    *plane = planel;
111
46974
}
112
113
static const uint8_t cga_mode45_index[6][4] = {
114
    [0] = { 0, 3,  5,   7 }, // mode4, palette#1, low intensity
115
    [1] = { 0, 2,  4,   6 }, // mode4, palette#2, low intensity
116
    [2] = { 0, 3,  4,   7 }, // mode5, low intensity
117
    [3] = { 0, 11, 13, 15 }, // mode4, palette#1, high intensity
118
    [4] = { 0, 10, 12, 14 }, // mode4, palette#2, high intensity
119
    [5] = { 0, 11, 12, 15 }, // mode5, high intensity
120
};
121
122
2
static int decode_frame(AVCodecContext *avctx,
123
                        void *data, int *got_frame,
124
                        AVPacket *avpkt)
125
{
126
2
    PicContext *s = avctx->priv_data;
127
2
    AVFrame *frame = data;
128
    uint32_t *palette;
129
    int bits_per_plane, bpp, etype, esize, npal, pos_after_pal;
130
    int i, x, y, plane, tmp, ret, val;
131
132
2
    bytestream2_init(&s->g, avpkt->data, avpkt->size);
133
134
2
    if (bytestream2_get_bytes_left(&s->g) < 11)
135
        return AVERROR_INVALIDDATA;
136
137
2
    if (bytestream2_get_le16u(&s->g) != 0x1234)
138
        return AVERROR_INVALIDDATA;
139
140
2
    s->width       = bytestream2_get_le16u(&s->g);
141
2
    s->height      = bytestream2_get_le16u(&s->g);
142
2
    bytestream2_skip(&s->g, 4);
143
2
    tmp            = bytestream2_get_byteu(&s->g);
144
2
    bits_per_plane = tmp & 0xF;
145
2
    s->nb_planes   = (tmp >> 4) + 1;
146
2
    bpp            = bits_per_plane * s->nb_planes;
147

2
    if (bits_per_plane > 8 || bpp < 1 || bpp > 32) {
148
        avpriv_request_sample(avctx, "Unsupported bit depth");
149
        return AVERROR_PATCHWELCOME;
150
    }
151
152


2
    if (bytestream2_peek_byte(&s->g) == 0xFF || bpp == 1 || bpp == 4 || bpp == 8) {
153
2
        bytestream2_skip(&s->g, 2);
154
2
        etype = bytestream2_get_le16(&s->g);
155
2
        esize = bytestream2_get_le16(&s->g);
156
2
        if (bytestream2_get_bytes_left(&s->g) < esize)
157
            return AVERROR_INVALIDDATA;
158
    } else {
159
        etype = -1;
160
        esize = 0;
161
    }
162
163
2
    avctx->pix_fmt = AV_PIX_FMT_PAL8;
164
165
2
    if (av_image_check_size(s->width, s->height, 0, avctx) < 0)
166
        return -1;
167

2
    if (s->width != avctx->width || s->height != avctx->height) {
168
1
        ret = ff_set_dimensions(avctx, s->width, s->height);
169
1
        if (ret < 0)
170
            return ret;
171
    }
172
173
2
    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
174
        return ret;
175
2
    memset(frame->data[0], 0, s->height * frame->linesize[0]);
176
2
    frame->pict_type           = AV_PICTURE_TYPE_I;
177
2
    frame->palette_has_changed = 1;
178
179
2
    pos_after_pal = bytestream2_tell(&s->g) + esize;
180
2
    palette = (uint32_t*)frame->data[1];
181

2
    if (etype == 1 && esize > 1 && bytestream2_peek_byte(&s->g) < 6) {
182
        int idx = bytestream2_get_byte(&s->g);
183
        npal = 4;
184
        for (i = 0; i < npal; i++)
185
            palette[i] = ff_cga_palette[ cga_mode45_index[idx][i] ];
186
2
    } else if (etype == 2) {
187
        npal = FFMIN(esize, 16);
188
        for (i = 0; i < npal; i++) {
189
            int pal_idx = bytestream2_get_byte(&s->g);
190
            palette[i]  = ff_cga_palette[FFMIN(pal_idx, 15)];
191
        }
192
2
    } else if (etype == 3) {
193
        npal = FFMIN(esize, 16);
194
        for (i = 0; i < npal; i++) {
195
            int pal_idx = bytestream2_get_byte(&s->g);
196
            palette[i]  = ff_ega_palette[FFMIN(pal_idx, 63)];
197
        }
198

2
    } else if (etype == 4 || etype == 5) {
199
2
        npal = FFMIN(esize / 3, 256);
200
34
        for (i = 0; i < npal; i++) {
201
32
            palette[i] = bytestream2_get_be24(&s->g) << 2;
202
32
            palette[i] |= 0xFFU << 24 | palette[i] >> 6 & 0x30303;
203
        }
204
    } else {
205
        if (bpp == 1) {
206
            npal = 2;
207
            palette[0] = 0xFF000000;
208
            palette[1] = 0xFFFFFFFF;
209
        } else if (bpp == 2) {
210
            npal = 4;
211
            for (i = 0; i < npal; i++)
212
                palette[i] = ff_cga_palette[ cga_mode45_index[0][i] ];
213
        } else {
214
            npal = 16;
215
            memcpy(palette, ff_cga_palette, npal * 4);
216
        }
217
    }
218
    // fill remaining palette entries
219
2
    memset(palette + npal, 0, AVPALETTE_SIZE - npal * 4);
220
    // skip remaining palette bytes
221
2
    bytestream2_seek(&s->g, pos_after_pal, SEEK_SET);
222
223
2
    val = 0;
224
2
    y = s->height - 1;
225
2
    if (bytestream2_get_le16(&s->g)) {
226
2
        x = 0;
227
2
        plane = 0;
228
10
        while (bytestream2_get_bytes_left(&s->g) >= 6) {
229
            int stop_size, marker, t1, t2;
230
231
8
            t1        = bytestream2_get_bytes_left(&s->g);
232
8
            t2        = bytestream2_get_le16(&s->g);
233
8
            stop_size = t1 - FFMIN(t1, t2);
234
            // ignore uncompressed block size
235
8
            bytestream2_skip(&s->g, 2);
236
8
            marker    = bytestream2_get_byte(&s->g);
237
238
46980
            while (plane < s->nb_planes &&
239
46980
                   bytestream2_get_bytes_left(&s->g) > stop_size) {
240
46974
                int run = 1;
241
46974
                val = bytestream2_get_byte(&s->g);
242
46974
                if (val == marker) {
243
2136
                    run = bytestream2_get_byte(&s->g);
244
2136
                    if (run == 0)
245
                        run = bytestream2_get_le16(&s->g);
246
2136
                    val = bytestream2_get_byte(&s->g);
247
                }
248
46974
                if (!bytestream2_get_bytes_left(&s->g))
249
2
                    break;
250
251
46972
                if (bits_per_plane == 8) {
252
                    picmemset_8bpp(s, frame, val, run, &x, &y);
253
                    if (y < 0)
254
                        goto finish;
255
                } else {
256
46972
                    picmemset(s, frame, val, run, &x, &y, &plane, bits_per_plane);
257
                }
258
            }
259
        }
260
261
2
        if (s->nb_planes - plane > 1)
262
            return AVERROR_INVALIDDATA;
263
264

2
        if (plane < s->nb_planes && x < avctx->width) {
265
2
            int run = (y + 1) * avctx->width - x;
266
2
            if (bits_per_plane == 8)
267
                picmemset_8bpp(s, frame, val, run, &x, &y);
268
            else
269
2
                picmemset(s, frame, val, run / (8 / bits_per_plane), &x, &y, &plane, bits_per_plane);
270
        }
271
    } else {
272
        while (y >= 0 && bytestream2_get_bytes_left(&s->g) > 0) {
273
            memcpy(frame->data[0] + y * frame->linesize[0], s->g.buffer, FFMIN(avctx->width, bytestream2_get_bytes_left(&s->g)));
274
            bytestream2_skip(&s->g, avctx->width);
275
            y--;
276
        }
277
    }
278
finish:
279
280
2
    *got_frame      = 1;
281
2
    return avpkt->size;
282
}
283
284
AVCodec ff_pictor_decoder = {
285
    .name           = "pictor",
286
    .long_name      = NULL_IF_CONFIG_SMALL("Pictor/PC Paint"),
287
    .type           = AVMEDIA_TYPE_VIDEO,
288
    .id             = AV_CODEC_ID_PICTOR,
289
    .priv_data_size = sizeof(PicContext),
290
    .decode         = decode_frame,
291
    .capabilities   = AV_CODEC_CAP_DR1,
292
};