FFmpeg coverage


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