/src/ffmpeg/libavcodec/pictordec.c
Line | Count | 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 | 717k | { |
44 | 2.53M | while (run > 0) { |
45 | 2.43M | uint8_t *d = frame->data[0] + *y * frame->linesize[0]; |
46 | 2.43M | if (*x + run >= s->width) { |
47 | 1.81M | int n = s->width - *x; |
48 | 1.81M | memset(d + *x, value, n); |
49 | 1.81M | run -= n; |
50 | 1.81M | *x = 0; |
51 | 1.81M | *y -= 1; |
52 | 1.81M | if (*y < 0) |
53 | 464 | break; |
54 | 1.81M | } else { |
55 | 621k | memset(d + *x, value, run); |
56 | 621k | *x += run; |
57 | 621k | break; |
58 | 621k | } |
59 | 2.43M | } |
60 | 717k | } |
61 | | |
62 | | static void picmemset(PicContext *s, AVFrame *frame, unsigned value, int run, |
63 | | int *x, int *y, int *plane, int bits_per_plane) |
64 | 798k | { |
65 | 798k | uint8_t *d; |
66 | 798k | int shift = *plane * bits_per_plane; |
67 | 798k | unsigned mask = ((1U << bits_per_plane) - 1) << shift; |
68 | 798k | int xl = *x; |
69 | 798k | int yl = *y; |
70 | 798k | int planel = *plane; |
71 | 798k | int pixels_per_value = 8/bits_per_plane; |
72 | 798k | value <<= shift; |
73 | | |
74 | 798k | d = frame->data[0] + yl * frame->linesize[0]; |
75 | 13.2M | while (run > 0) { |
76 | 12.4M | int j; |
77 | 43.9M | for (j = 8-bits_per_plane; j >= 0; j -= bits_per_plane) { |
78 | 31.5M | d[xl] |= (value >> j) & mask; |
79 | 31.5M | xl += 1; |
80 | 40.0M | while (xl == s->width) { |
81 | 8.57M | yl -= 1; |
82 | 8.57M | xl = 0; |
83 | 8.57M | if (yl < 0) { |
84 | 3.36k | yl = s->height - 1; |
85 | 3.36k | planel += 1; |
86 | 3.36k | if (planel >= s->nb_planes) |
87 | 1.02k | goto end; |
88 | 2.34k | value <<= bits_per_plane; |
89 | 2.34k | mask <<= bits_per_plane; |
90 | 2.34k | } |
91 | 8.57M | d = frame->data[0] + yl * frame->linesize[0]; |
92 | 8.57M | if (s->nb_planes == 1 && |
93 | 8.57M | run*pixels_per_value >= s->width && |
94 | 8.57M | pixels_per_value < (s->width / pixels_per_value * pixels_per_value) |
95 | 8.57M | ) { |
96 | 9.13M | for (; xl < pixels_per_value; xl ++) { |
97 | 7.30M | j = (j < bits_per_plane ? 8 : j) - bits_per_plane; |
98 | 7.30M | d[xl] |= (value >> j) & mask; |
99 | 7.30M | } |
100 | 1.83M | av_memcpy_backptr(d+xl, pixels_per_value, s->width - xl); |
101 | 1.83M | run -= s->width / pixels_per_value; |
102 | 1.83M | xl = s->width / pixels_per_value * pixels_per_value; |
103 | 1.83M | } |
104 | 8.57M | } |
105 | 31.5M | } |
106 | 12.4M | run--; |
107 | 12.4M | } |
108 | 798k | end: |
109 | 798k | *x = xl; |
110 | 798k | *y = yl; |
111 | 798k | *plane = planel; |
112 | 798k | } |
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 | | static int decode_frame(AVCodecContext *avctx, AVFrame *frame, |
124 | | int *got_frame, AVPacket *avpkt) |
125 | 311k | { |
126 | 311k | PicContext *s = avctx->priv_data; |
127 | 311k | uint32_t *palette; |
128 | 311k | int bits_per_plane, bpp, etype, esize, npal, pos_after_pal; |
129 | 311k | int i, x, y, plane, tmp, ret, val; |
130 | | |
131 | 311k | bytestream2_init(&s->g, avpkt->data, avpkt->size); |
132 | | |
133 | 311k | if (bytestream2_get_bytes_left(&s->g) < 11) |
134 | 171k | return AVERROR_INVALIDDATA; |
135 | | |
136 | 139k | if (bytestream2_get_le16u(&s->g) != 0x1234) |
137 | 9.64k | return AVERROR_INVALIDDATA; |
138 | | |
139 | 130k | s->width = bytestream2_get_le16u(&s->g); |
140 | 130k | s->height = bytestream2_get_le16u(&s->g); |
141 | 130k | bytestream2_skip(&s->g, 4); |
142 | 130k | tmp = bytestream2_get_byteu(&s->g); |
143 | 130k | bits_per_plane = tmp & 0xF; |
144 | 130k | s->nb_planes = (tmp >> 4) + 1; |
145 | 130k | bpp = bits_per_plane * s->nb_planes; |
146 | 130k | if (bits_per_plane > 8 || bpp < 1 || bpp > 32) { |
147 | 1.13k | avpriv_request_sample(avctx, "Unsupported bit depth"); |
148 | 1.13k | return AVERROR_PATCHWELCOME; |
149 | 1.13k | } |
150 | | |
151 | 128k | if (bytestream2_peek_byte(&s->g) == 0xFF || bpp == 1 || bpp == 4 || bpp == 8) { |
152 | 120k | bytestream2_skip(&s->g, 2); |
153 | 120k | etype = bytestream2_get_le16(&s->g); |
154 | 120k | esize = bytestream2_get_le16(&s->g); |
155 | 120k | if (bytestream2_get_bytes_left(&s->g) < esize) |
156 | 744 | return AVERROR_INVALIDDATA; |
157 | 120k | } else { |
158 | 8.33k | etype = -1; |
159 | 8.33k | esize = 0; |
160 | 8.33k | } |
161 | | |
162 | 128k | avctx->pix_fmt = AV_PIX_FMT_PAL8; |
163 | | |
164 | 128k | if (av_image_check_size(s->width, s->height, 0, avctx) < 0) |
165 | 924 | 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 | | that's 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 | 127k | if (bytestream2_get_bytes_left(&s->g) < s->width * s->height / 65535 * 5) |
183 | 10.8k | return AVERROR_INVALIDDATA; |
184 | | |
185 | 116k | if (s->width != avctx->width || s->height != avctx->height) { |
186 | 5.66k | ret = ff_set_dimensions(avctx, s->width, s->height); |
187 | 5.66k | if (ret < 0) |
188 | 194 | return ret; |
189 | 5.66k | } |
190 | | |
191 | 116k | if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) |
192 | 194 | return ret; |
193 | 116k | memset(frame->data[0], 0, s->height * frame->linesize[0]); |
194 | 116k | frame->pict_type = AV_PICTURE_TYPE_I; |
195 | | |
196 | 116k | pos_after_pal = bytestream2_tell(&s->g) + esize; |
197 | 116k | palette = (uint32_t*)frame->data[1]; |
198 | 116k | if (etype == 1 && esize > 1 && bytestream2_peek_byte(&s->g) < 6) { |
199 | 650 | int idx = bytestream2_get_byte(&s->g); |
200 | 650 | npal = 4; |
201 | 3.25k | for (i = 0; i < npal; i++) |
202 | 2.60k | palette[i] = ff_cga_palette[ cga_mode45_index[idx][i] ]; |
203 | 115k | } else if (etype == 2) { |
204 | 681 | npal = FFMIN(esize, 16); |
205 | 5.20k | for (i = 0; i < npal; i++) { |
206 | 4.52k | int pal_idx = bytestream2_get_byte(&s->g); |
207 | 4.52k | palette[i] = ff_cga_palette[FFMIN(pal_idx, 15)]; |
208 | 4.52k | } |
209 | 114k | } else if (etype == 3) { |
210 | 806 | npal = FFMIN(esize, 16); |
211 | 6.49k | for (i = 0; i < npal; i++) { |
212 | 5.68k | int pal_idx = bytestream2_get_byte(&s->g); |
213 | 5.68k | palette[i] = ff_ega_palette[FFMIN(pal_idx, 63)]; |
214 | 5.68k | } |
215 | 113k | } else if (etype == 4 || etype == 5) { |
216 | 894 | npal = FFMIN(esize / 3, 256); |
217 | 57.7k | for (i = 0; i < npal; i++) { |
218 | 56.8k | palette[i] = bytestream2_get_be24(&s->g) << 2; |
219 | 56.8k | palette[i] |= 0xFFU << 24 | palette[i] >> 6 & 0x30303; |
220 | 56.8k | } |
221 | 113k | } else { |
222 | 113k | if (bpp == 1) { |
223 | 945 | npal = 2; |
224 | 945 | palette[0] = 0xFF000000; |
225 | 945 | palette[1] = 0xFFFFFFFF; |
226 | 112k | } else if (bpp == 2) { |
227 | 2.02k | npal = 4; |
228 | 10.1k | for (i = 0; i < npal; i++) |
229 | 8.08k | palette[i] = ff_cga_palette[ cga_mode45_index[0][i] ]; |
230 | 110k | } else { |
231 | 110k | npal = 16; |
232 | 110k | memcpy(palette, ff_cga_palette, npal * 4); |
233 | 110k | } |
234 | 113k | } |
235 | | // fill remaining palette entries |
236 | 116k | memset(palette + npal, 0, AVPALETTE_SIZE - npal * 4); |
237 | | // skip remaining palette bytes |
238 | 116k | bytestream2_seek(&s->g, pos_after_pal, SEEK_SET); |
239 | | |
240 | 116k | val = 0; |
241 | 116k | y = s->height - 1; |
242 | 116k | if (bytestream2_get_le16(&s->g)) { |
243 | 2.70k | x = 0; |
244 | 2.70k | plane = 0; |
245 | 1.68M | while (bytestream2_get_bytes_left(&s->g) >= 6) { |
246 | 1.67M | int stop_size, marker, t1, t2; |
247 | | |
248 | 1.67M | t1 = bytestream2_get_bytes_left(&s->g); |
249 | 1.67M | t2 = bytestream2_get_le16(&s->g); |
250 | 1.67M | stop_size = t1 - FFMIN(t1, t2); |
251 | | // ignore uncompressed block size |
252 | 1.67M | bytestream2_skip(&s->g, 2); |
253 | 1.67M | marker = bytestream2_get_byte(&s->g); |
254 | | |
255 | 3.19M | while (plane < s->nb_planes && |
256 | 3.19M | bytestream2_get_bytes_left(&s->g) > stop_size) { |
257 | 1.51M | int run = 1; |
258 | 1.51M | val = bytestream2_get_byte(&s->g); |
259 | 1.51M | if (val == marker) { |
260 | 169k | run = bytestream2_get_byte(&s->g); |
261 | 169k | if (run == 0) |
262 | 154k | run = bytestream2_get_le16(&s->g); |
263 | 169k | val = bytestream2_get_byte(&s->g); |
264 | 169k | } |
265 | | |
266 | 1.51M | if (bits_per_plane == 8) { |
267 | 717k | picmemset_8bpp(s, frame, val, run, &x, &y); |
268 | 717k | if (y < 0) |
269 | 230 | goto finish; |
270 | 797k | } else { |
271 | 797k | picmemset(s, frame, val, run, &x, &y, &plane, bits_per_plane); |
272 | 797k | } |
273 | 1.51M | } |
274 | 1.67M | } |
275 | | |
276 | 2.47k | if (s->nb_planes - plane > 1) |
277 | 819 | return AVERROR_INVALIDDATA; |
278 | | |
279 | 1.65k | if (plane < s->nb_planes && x < avctx->width) { |
280 | 1.27k | int run = (y + 1) * avctx->width - x; |
281 | 1.27k | if (bits_per_plane == 8) |
282 | 234 | picmemset_8bpp(s, frame, val, run, &x, &y); |
283 | 1.03k | else |
284 | 1.03k | picmemset(s, frame, val, run / (8 / bits_per_plane), &x, &y, &plane, bits_per_plane); |
285 | 1.27k | } |
286 | 113k | } else { |
287 | 378k | while (y >= 0 && bytestream2_get_bytes_left(&s->g) > 0) { |
288 | 264k | memcpy(frame->data[0] + y * frame->linesize[0], s->g.buffer, FFMIN(avctx->width, bytestream2_get_bytes_left(&s->g))); |
289 | 264k | bytestream2_skip(&s->g, avctx->width); |
290 | 264k | y--; |
291 | 264k | } |
292 | 113k | } |
293 | 115k | finish: |
294 | | |
295 | 115k | *got_frame = 1; |
296 | 115k | return avpkt->size; |
297 | 116k | } |
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 | | }; |