FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/pictordec.c
Date: 2025-04-25 22:50:00
Exec Total Coverage
Lines: 95 165 57.6%
Functions: 2 3 66.7%
Branches: 46 118 39.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 "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 {
44 while (run > 0) {
45 uint8_t *d = frame->data[0] + *y * frame->linesize[0];
46 if (*x + run >= s->width) {
47 int n = s->width - *x;
48 memset(d + *x, value, n);
49 run -= n;
50 *x = 0;
51 *y -= 1;
52 if (*y < 0)
53 break;
54 } else {
55 memset(d + *x, value, run);
56 *x += run;
57 break;
58 }
59 }
60 }
61
62 46974 static void picmemset(PicContext *s, AVFrame *frame, unsigned value, int run,
63 int *x, int *y, int *plane, int bits_per_plane)
64 {
65 uint8_t *d;
66 46974 int shift = *plane * bits_per_plane;
67 46974 unsigned mask = ((1U << bits_per_plane) - 1) << shift;
68 46974 int xl = *x;
69 46974 int yl = *y;
70 46974 int planel = *plane;
71 46974 int pixels_per_value = 8/bits_per_plane;
72 46974 value <<= shift;
73
74 46974 d = frame->data[0] + yl * frame->linesize[0];
75
2/2
✓ Branch 0 taken 64272 times.
✓ Branch 1 taken 46972 times.
111244 while (run > 0) {
76 int j;
77
2/2
✓ Branch 0 taken 514176 times.
✓ Branch 1 taken 64270 times.
578446 for (j = 8-bits_per_plane; j >= 0; j -= bits_per_plane) {
78 514176 d[xl] |= (value >> j) & mask;
79 514176 xl += 1;
80
2/2
✓ Branch 0 taken 1648 times.
✓ Branch 1 taken 514174 times.
515822 while (xl == s->width) {
81 1648 yl -= 1;
82 1648 xl = 0;
83
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1640 times.
1648 if (yl < 0) {
84 8 yl = s->height - 1;
85 8 planel += 1;
86
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
8 if (planel >= s->nb_planes)
87 2 goto end;
88 6 value <<= bits_per_plane;
89 6 mask <<= bits_per_plane;
90 }
91 1646 d = frame->data[0] + yl * frame->linesize[0];
92
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1646 times.
1646 if (s->nb_planes == 1 &&
93 run*pixels_per_value >= s->width &&
94 pixels_per_value < (s->width / pixels_per_value * pixels_per_value)
95 ) {
96 for (; xl < pixels_per_value; xl ++) {
97 j = (j < bits_per_plane ? 8 : j) - bits_per_plane;
98 d[xl] |= (value >> j) & mask;
99 }
100 av_memcpy_backptr(d+xl, pixels_per_value, s->width - xl);
101 run -= s->width / pixels_per_value;
102 xl = s->width / pixels_per_value * pixels_per_value;
103 }
104 }
105 }
106 64270 run--;
107 }
108 46972 end:
109 46974 *x = xl;
110 46974 *y = yl;
111 46974 *plane = planel;
112 46974 }
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 2 static int decode_frame(AVCodecContext *avctx, AVFrame *frame,
124 int *got_frame, AVPacket *avpkt)
125 {
126 2 PicContext *s = avctx->priv_data;
127 uint32_t *palette;
128 int bits_per_plane, bpp, etype, esize, npal, pos_after_pal;
129 int i, x, y, plane, tmp, ret, val;
130
131 2 bytestream2_init(&s->g, avpkt->data, avpkt->size);
132
133
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (bytestream2_get_bytes_left(&s->g) < 11)
134 return AVERROR_INVALIDDATA;
135
136
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (bytestream2_get_le16u(&s->g) != 0x1234)
137 return AVERROR_INVALIDDATA;
138
139 2 s->width = bytestream2_get_le16u(&s->g);
140 2 s->height = bytestream2_get_le16u(&s->g);
141 2 bytestream2_skip(&s->g, 4);
142 2 tmp = bytestream2_get_byteu(&s->g);
143 2 bits_per_plane = tmp & 0xF;
144 2 s->nb_planes = (tmp >> 4) + 1;
145 2 bpp = bits_per_plane * s->nb_planes;
146
3/6
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
2 if (bits_per_plane > 8 || bpp < 1 || bpp > 32) {
147 avpriv_request_sample(avctx, "Unsupported bit depth");
148 return AVERROR_PATCHWELCOME;
149 }
150
151
1/8
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
2 if (bytestream2_peek_byte(&s->g) == 0xFF || bpp == 1 || bpp == 4 || bpp == 8) {
152 2 bytestream2_skip(&s->g, 2);
153 2 etype = bytestream2_get_le16(&s->g);
154 2 esize = bytestream2_get_le16(&s->g);
155
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (bytestream2_get_bytes_left(&s->g) < esize)
156 return AVERROR_INVALIDDATA;
157 } else {
158 etype = -1;
159 esize = 0;
160 }
161
162 2 avctx->pix_fmt = AV_PIX_FMT_PAL8;
163
164
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (av_image_check_size(s->width, s->height, 0, avctx) < 0)
165 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 thats 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
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (bytestream2_get_bytes_left(&s->g) < s->width * s->height / 65535 * 5)
183 return AVERROR_INVALIDDATA;
184
185
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
2 if (s->width != avctx->width || s->height != avctx->height) {
186 1 ret = ff_set_dimensions(avctx, s->width, s->height);
187
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
188 return ret;
189 }
190
191
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
192 return ret;
193 2 memset(frame->data[0], 0, s->height * frame->linesize[0]);
194 2 frame->pict_type = AV_PICTURE_TYPE_I;
195
196 2 pos_after_pal = bytestream2_tell(&s->g) + esize;
197 2 palette = (uint32_t*)frame->data[1];
198
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
2 if (etype == 1 && esize > 1 && bytestream2_peek_byte(&s->g) < 6) {
199 int idx = bytestream2_get_byte(&s->g);
200 npal = 4;
201 for (i = 0; i < npal; i++)
202 palette[i] = ff_cga_palette[ cga_mode45_index[idx][i] ];
203
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 } else if (etype == 2) {
204 npal = FFMIN(esize, 16);
205 for (i = 0; i < npal; i++) {
206 int pal_idx = bytestream2_get_byte(&s->g);
207 palette[i] = ff_cga_palette[FFMIN(pal_idx, 15)];
208 }
209
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 } else if (etype == 3) {
210 npal = FFMIN(esize, 16);
211 for (i = 0; i < npal; i++) {
212 int pal_idx = bytestream2_get_byte(&s->g);
213 palette[i] = ff_ega_palette[FFMIN(pal_idx, 63)];
214 }
215
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 } else if (etype == 4 || etype == 5) {
216
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 npal = FFMIN(esize / 3, 256);
217
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 2 times.
34 for (i = 0; i < npal; i++) {
218 32 palette[i] = bytestream2_get_be24(&s->g) << 2;
219 32 palette[i] |= 0xFFU << 24 | palette[i] >> 6 & 0x30303;
220 }
221 } else {
222 if (bpp == 1) {
223 npal = 2;
224 palette[0] = 0xFF000000;
225 palette[1] = 0xFFFFFFFF;
226 } else if (bpp == 2) {
227 npal = 4;
228 for (i = 0; i < npal; i++)
229 palette[i] = ff_cga_palette[ cga_mode45_index[0][i] ];
230 } else {
231 npal = 16;
232 memcpy(palette, ff_cga_palette, npal * 4);
233 }
234 }
235 // fill remaining palette entries
236 2 memset(palette + npal, 0, AVPALETTE_SIZE - npal * 4);
237 // skip remaining palette bytes
238 2 bytestream2_seek(&s->g, pos_after_pal, SEEK_SET);
239
240 2 val = 0;
241 2 y = s->height - 1;
242
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (bytestream2_get_le16(&s->g)) {
243 2 x = 0;
244 2 plane = 0;
245
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 2 times.
10 while (bytestream2_get_bytes_left(&s->g) >= 6) {
246 int stop_size, marker, t1, t2;
247
248 8 t1 = bytestream2_get_bytes_left(&s->g);
249 8 t2 = bytestream2_get_le16(&s->g);
250 8 stop_size = t1 - FFMIN(t1, t2);
251 // ignore uncompressed block size
252 8 bytestream2_skip(&s->g, 2);
253 8 marker = bytestream2_get_byte(&s->g);
254
255
4/4
✓ Branch 0 taken 46980 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 46974 times.
✓ Branch 3 taken 6 times.
93962 while (plane < s->nb_planes &&
256 46980 bytestream2_get_bytes_left(&s->g) > stop_size) {
257 46974 int run = 1;
258 46974 val = bytestream2_get_byte(&s->g);
259
2/2
✓ Branch 0 taken 2136 times.
✓ Branch 1 taken 44838 times.
46974 if (val == marker) {
260 2136 run = bytestream2_get_byte(&s->g);
261
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2136 times.
2136 if (run == 0)
262 run = bytestream2_get_le16(&s->g);
263 2136 val = bytestream2_get_byte(&s->g);
264 }
265
266
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46974 times.
46974 if (bits_per_plane == 8) {
267 picmemset_8bpp(s, frame, val, run, &x, &y);
268 if (y < 0)
269 goto finish;
270 } else {
271 46974 picmemset(s, frame, val, run, &x, &y, &plane, bits_per_plane);
272 }
273 }
274 }
275
276
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (s->nb_planes - plane > 1)
277 return AVERROR_INVALIDDATA;
278
279
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2 if (plane < s->nb_planes && x < avctx->width) {
280 int run = (y + 1) * avctx->width - x;
281 if (bits_per_plane == 8)
282 picmemset_8bpp(s, frame, val, run, &x, &y);
283 else
284 picmemset(s, frame, val, run / (8 / bits_per_plane), &x, &y, &plane, bits_per_plane);
285 }
286 } else {
287 while (y >= 0 && bytestream2_get_bytes_left(&s->g) > 0) {
288 memcpy(frame->data[0] + y * frame->linesize[0], s->g.buffer, FFMIN(avctx->width, bytestream2_get_bytes_left(&s->g)));
289 bytestream2_skip(&s->g, avctx->width);
290 y--;
291 }
292 }
293 finish:
294
295 2 *got_frame = 1;
296 2 return avpkt->size;
297 }
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 };
308