FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/pictordec.c
Date: 2023-10-02 11:06:47
Exec Total Coverage
Lines: 96 166 57.8%
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 "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 #if FF_API_PALETTE_HAS_CHANGED
195 FF_DISABLE_DEPRECATION_WARNINGS
196 2 frame->palette_has_changed = 1;
197 FF_ENABLE_DEPRECATION_WARNINGS
198 #endif
199
200 2 pos_after_pal = bytestream2_tell(&s->g) + esize;
201 2 palette = (uint32_t*)frame->data[1];
202
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) {
203 int idx = bytestream2_get_byte(&s->g);
204 npal = 4;
205 for (i = 0; i < npal; i++)
206 palette[i] = ff_cga_palette[ cga_mode45_index[idx][i] ];
207
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 } else if (etype == 2) {
208 npal = FFMIN(esize, 16);
209 for (i = 0; i < npal; i++) {
210 int pal_idx = bytestream2_get_byte(&s->g);
211 palette[i] = ff_cga_palette[FFMIN(pal_idx, 15)];
212 }
213
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 } else if (etype == 3) {
214 npal = FFMIN(esize, 16);
215 for (i = 0; i < npal; i++) {
216 int pal_idx = bytestream2_get_byte(&s->g);
217 palette[i] = ff_ega_palette[FFMIN(pal_idx, 63)];
218 }
219
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) {
220
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 npal = FFMIN(esize / 3, 256);
221
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 2 times.
34 for (i = 0; i < npal; i++) {
222 32 palette[i] = bytestream2_get_be24(&s->g) << 2;
223 32 palette[i] |= 0xFFU << 24 | palette[i] >> 6 & 0x30303;
224 }
225 } else {
226 if (bpp == 1) {
227 npal = 2;
228 palette[0] = 0xFF000000;
229 palette[1] = 0xFFFFFFFF;
230 } else if (bpp == 2) {
231 npal = 4;
232 for (i = 0; i < npal; i++)
233 palette[i] = ff_cga_palette[ cga_mode45_index[0][i] ];
234 } else {
235 npal = 16;
236 memcpy(palette, ff_cga_palette, npal * 4);
237 }
238 }
239 // fill remaining palette entries
240 2 memset(palette + npal, 0, AVPALETTE_SIZE - npal * 4);
241 // skip remaining palette bytes
242 2 bytestream2_seek(&s->g, pos_after_pal, SEEK_SET);
243
244 2 val = 0;
245 2 y = s->height - 1;
246
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (bytestream2_get_le16(&s->g)) {
247 2 x = 0;
248 2 plane = 0;
249
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 2 times.
10 while (bytestream2_get_bytes_left(&s->g) >= 6) {
250 int stop_size, marker, t1, t2;
251
252 8 t1 = bytestream2_get_bytes_left(&s->g);
253 8 t2 = bytestream2_get_le16(&s->g);
254 8 stop_size = t1 - FFMIN(t1, t2);
255 // ignore uncompressed block size
256 8 bytestream2_skip(&s->g, 2);
257 8 marker = bytestream2_get_byte(&s->g);
258
259
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 &&
260 46980 bytestream2_get_bytes_left(&s->g) > stop_size) {
261 46974 int run = 1;
262 46974 val = bytestream2_get_byte(&s->g);
263
2/2
✓ Branch 0 taken 2136 times.
✓ Branch 1 taken 44838 times.
46974 if (val == marker) {
264 2136 run = bytestream2_get_byte(&s->g);
265
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2136 times.
2136 if (run == 0)
266 run = bytestream2_get_le16(&s->g);
267 2136 val = bytestream2_get_byte(&s->g);
268 }
269
270
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46974 times.
46974 if (bits_per_plane == 8) {
271 picmemset_8bpp(s, frame, val, run, &x, &y);
272 if (y < 0)
273 goto finish;
274 } else {
275 46974 picmemset(s, frame, val, run, &x, &y, &plane, bits_per_plane);
276 }
277 }
278 }
279
280
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (s->nb_planes - plane > 1)
281 return AVERROR_INVALIDDATA;
282
283
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) {
284 int run = (y + 1) * avctx->width - x;
285 if (bits_per_plane == 8)
286 picmemset_8bpp(s, frame, val, run, &x, &y);
287 else
288 picmemset(s, frame, val, run / (8 / bits_per_plane), &x, &y, &plane, bits_per_plane);
289 }
290 } else {
291 while (y >= 0 && bytestream2_get_bytes_left(&s->g) > 0) {
292 memcpy(frame->data[0] + y * frame->linesize[0], s->g.buffer, FFMIN(avctx->width, bytestream2_get_bytes_left(&s->g)));
293 bytestream2_skip(&s->g, avctx->width);
294 y--;
295 }
296 }
297 finish:
298
299 2 *got_frame = 1;
300 2 return avpkt->size;
301 }
302
303 const FFCodec ff_pictor_decoder = {
304 .p.name = "pictor",
305 CODEC_LONG_NAME("Pictor/PC Paint"),
306 .p.type = AVMEDIA_TYPE_VIDEO,
307 .p.id = AV_CODEC_ID_PICTOR,
308 .p.capabilities = AV_CODEC_CAP_DR1,
309 .priv_data_size = sizeof(PicContext),
310 FF_CODEC_DECODE_CB(decode_frame),
311 };
312