FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/pictordec.c
Date: 2022-11-28 23:49:43
Exec Total Coverage
Lines: 96 165 58.2%
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 "avcodec.h"
29 #include "bytestream.h"
30 #include "cga_data.h"
31 #include "codec_internal.h"
32 #include "decode.h"
33
34 typedef struct PicContext {
35 int width, height;
36 int nb_planes;
37 GetByteContext g;
38 } PicContext;
39
40 static void picmemset_8bpp(PicContext *s, AVFrame *frame, int value, int run,
41 int *x, int *y)
42 {
43 while (run > 0) {
44 uint8_t *d = frame->data[0] + *y * frame->linesize[0];
45 if (*x + run >= s->width) {
46 int n = s->width - *x;
47 memset(d + *x, value, n);
48 run -= n;
49 *x = 0;
50 *y -= 1;
51 if (*y < 0)
52 break;
53 } else {
54 memset(d + *x, value, run);
55 *x += run;
56 break;
57 }
58 }
59 }
60
61 46974 static void picmemset(PicContext *s, AVFrame *frame, unsigned value, int run,
62 int *x, int *y, int *plane, int bits_per_plane)
63 {
64 uint8_t *d;
65 46974 int shift = *plane * bits_per_plane;
66 46974 unsigned mask = ((1U << bits_per_plane) - 1) << shift;
67 46974 int xl = *x;
68 46974 int yl = *y;
69 46974 int planel = *plane;
70 46974 int pixels_per_value = 8/bits_per_plane;
71 46974 value <<= shift;
72
73 46974 d = frame->data[0] + yl * frame->linesize[0];
74
2/2
✓ Branch 0 taken 64272 times.
✓ Branch 1 taken 46972 times.
111244 while (run > 0) {
75 int j;
76
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) {
77 514176 d[xl] |= (value >> j) & mask;
78 514176 xl += 1;
79
2/2
✓ Branch 0 taken 1648 times.
✓ Branch 1 taken 514174 times.
515822 while (xl == s->width) {
80 1648 yl -= 1;
81 1648 xl = 0;
82
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1640 times.
1648 if (yl < 0) {
83 8 yl = s->height - 1;
84 8 planel += 1;
85
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
8 if (planel >= s->nb_planes)
86 2 goto end;
87 6 value <<= bits_per_plane;
88 6 mask <<= bits_per_plane;
89 }
90 1646 d = frame->data[0] + yl * frame->linesize[0];
91
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1646 times.
1646 if (s->nb_planes == 1 &&
92 run*pixels_per_value >= s->width &&
93 pixels_per_value < (s->width / pixels_per_value * pixels_per_value)
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 / pixels_per_value * pixels_per_value;
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, AVFrame *frame,
123 int *got_frame, AVPacket *avpkt)
124 {
125 2 PicContext *s = avctx->priv_data;
126 uint32_t *palette;
127 int bits_per_plane, bpp, etype, esize, npal, pos_after_pal;
128 int i, x, y, plane, tmp, ret, val;
129
130 2 bytestream2_init(&s->g, avpkt->data, avpkt->size);
131
132
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (bytestream2_get_bytes_left(&s->g) < 11)
133 return AVERROR_INVALIDDATA;
134
135
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (bytestream2_get_le16u(&s->g) != 0x1234)
136 return AVERROR_INVALIDDATA;
137
138 2 s->width = bytestream2_get_le16u(&s->g);
139 2 s->height = bytestream2_get_le16u(&s->g);
140 2 bytestream2_skip(&s->g, 4);
141 2 tmp = bytestream2_get_byteu(&s->g);
142 2 bits_per_plane = tmp & 0xF;
143 2 s->nb_planes = (tmp >> 4) + 1;
144 2 bpp = bits_per_plane * s->nb_planes;
145
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) {
146 avpriv_request_sample(avctx, "Unsupported bit depth");
147 return AVERROR_PATCHWELCOME;
148 }
149
150
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) {
151 2 bytestream2_skip(&s->g, 2);
152 2 etype = bytestream2_get_le16(&s->g);
153 2 esize = bytestream2_get_le16(&s->g);
154
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (bytestream2_get_bytes_left(&s->g) < esize)
155 return AVERROR_INVALIDDATA;
156 } else {
157 etype = -1;
158 esize = 0;
159 }
160
161 2 avctx->pix_fmt = AV_PIX_FMT_PAL8;
162
163
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (av_image_check_size(s->width, s->height, 0, avctx) < 0)
164 return -1;
165
166 /*
167 There are 2 coding modes, RLE and RAW.
168 Undamaged RAW should be proportional to W*H and thus bigger than RLE
169 RLE codes the most compressed runs by
170 1 byte for val (=marker)
171 1 byte run (=0)
172 2 bytes run
173 1 byte val
174 thats 5 bytes and the maximum run we can code is 65535
175
176 The RLE decoder can exit prematurly but it does not on any image available
177 Based on this the formula is assumed correct for undamaged images.
178 If an image is found which exploits the special end
179 handling and breaks this formula then this needs to be adapted.
180 */
181
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)
182 return AVERROR_INVALIDDATA;
183
184
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) {
185 1 ret = ff_set_dimensions(avctx, s->width, s->height);
186
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
187 return ret;
188 }
189
190
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
191 return ret;
192 2 memset(frame->data[0], 0, s->height * frame->linesize[0]);
193 2 frame->pict_type = AV_PICTURE_TYPE_I;
194 2 frame->palette_has_changed = 1;
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