Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * QuickDraw (qdrw) codec | ||
3 | * Copyright (c) 2004 Konstantin Shishkov | ||
4 | * Copyright (c) 2015 Vittorio Giovara | ||
5 | * | ||
6 | * This file is part of FFmpeg. | ||
7 | * | ||
8 | * FFmpeg is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU Lesser General Public | ||
10 | * License as published by the Free Software Foundation; either | ||
11 | * version 2.1 of the License, or (at your option) any later version. | ||
12 | * | ||
13 | * FFmpeg is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * Lesser General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU Lesser General Public | ||
19 | * License along with FFmpeg; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
21 | */ | ||
22 | |||
23 | /** | ||
24 | * @file | ||
25 | * Apple QuickDraw codec. | ||
26 | * https://developer.apple.com/legacy/library/documentation/mac/QuickDraw/QuickDraw-461.html | ||
27 | */ | ||
28 | |||
29 | #include "libavutil/common.h" | ||
30 | #include "libavutil/intreadwrite.h" | ||
31 | #include "avcodec.h" | ||
32 | #include "bytestream.h" | ||
33 | #include "codec_internal.h" | ||
34 | #include "decode.h" | ||
35 | |||
36 | enum QuickdrawOpcodes { | ||
37 | CLIP = 0x0001, | ||
38 | PACKBITSRECT = 0x0098, | ||
39 | PACKBITSRGN, | ||
40 | DIRECTBITSRECT, | ||
41 | DIRECTBITSRGN, | ||
42 | SHORTCOMMENT = 0x00A0, | ||
43 | LONGCOMMENT, | ||
44 | |||
45 | EOP = 0x00FF, | ||
46 | }; | ||
47 | |||
48 | 13 | static int parse_palette(AVCodecContext *avctx, GetByteContext *gbc, | |
49 | uint32_t *pal, int colors, int pixmap) | ||
50 | { | ||
51 | int i; | ||
52 | |||
53 |
2/2✓ Branch 0 taken 3328 times.
✓ Branch 1 taken 13 times.
|
3341 | for (i = 0; i <= colors; i++) { |
54 | uint8_t r, g, b; | ||
55 | 3328 | unsigned int idx = bytestream2_get_be16(gbc); /* color index */ | |
56 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 3328 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
3328 | if (idx > 255 && !pixmap) { |
57 | ✗ | av_log(avctx, AV_LOG_WARNING, | |
58 | "Palette index out of range: %u\n", idx); | ||
59 | ✗ | bytestream2_skip(gbc, 6); | |
60 | ✗ | continue; | |
61 | } | ||
62 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3328 times.
|
3328 | if (avctx->pix_fmt != AV_PIX_FMT_PAL8) |
63 | ✗ | return AVERROR_INVALIDDATA; | |
64 | 3328 | r = bytestream2_get_byte(gbc); | |
65 | 3328 | bytestream2_skip(gbc, 1); | |
66 | 3328 | g = bytestream2_get_byte(gbc); | |
67 | 3328 | bytestream2_skip(gbc, 1); | |
68 | 3328 | b = bytestream2_get_byte(gbc); | |
69 | 3328 | bytestream2_skip(gbc, 1); | |
70 |
1/2✓ Branch 0 taken 3328 times.
✗ Branch 1 not taken.
|
3328 | pal[pixmap ? i : idx] = (0xFFU << 24) | (r << 16) | (g << 8) | b; |
71 | } | ||
72 | 13 | return 0; | |
73 | } | ||
74 | |||
75 | ✗ | static int decode_rle_bpp2(AVCodecContext *avctx, AVFrame *p, GetByteContext *gbc) | |
76 | { | ||
77 | ✗ | int offset = avctx->width; | |
78 | ✗ | uint8_t *outdata = p->data[0]; | |
79 | int i, j; | ||
80 | |||
81 | ✗ | for (i = 0; i < avctx->height; i++) { | |
82 | int size, left, code, pix; | ||
83 | ✗ | uint8_t *out = outdata; | |
84 | ✗ | int pos = 0; | |
85 | |||
86 | /* size of packed line */ | ||
87 | ✗ | if (offset / 4 > 200) | |
88 | ✗ | size = left = bytestream2_get_be16(gbc); | |
89 | else | ||
90 | ✗ | size = left = bytestream2_get_byte(gbc); | |
91 | ✗ | if (bytestream2_get_bytes_left(gbc) < size) | |
92 | ✗ | return AVERROR_INVALIDDATA; | |
93 | |||
94 | /* decode line */ | ||
95 | ✗ | while (left > 0) { | |
96 | ✗ | code = bytestream2_get_byte(gbc); | |
97 | ✗ | if (code & 0x80 ) { /* run */ | |
98 | ✗ | pix = bytestream2_get_byte(gbc); | |
99 | ✗ | for (j = 0; j < 257 - code; j++) { | |
100 | ✗ | if (pos < offset) | |
101 | ✗ | out[pos++] = (pix & 0xC0) >> 6; | |
102 | ✗ | if (pos < offset) | |
103 | ✗ | out[pos++] = (pix & 0x30) >> 4; | |
104 | ✗ | if (pos < offset) | |
105 | ✗ | out[pos++] = (pix & 0x0C) >> 2; | |
106 | ✗ | if (pos < offset) | |
107 | ✗ | out[pos++] = (pix & 0x03); | |
108 | } | ||
109 | ✗ | left -= 2; | |
110 | } else { /* copy */ | ||
111 | ✗ | for (j = 0; j < code + 1; j++) { | |
112 | ✗ | pix = bytestream2_get_byte(gbc); | |
113 | ✗ | if (pos < offset) | |
114 | ✗ | out[pos++] = (pix & 0xC0) >> 6; | |
115 | ✗ | if (pos < offset) | |
116 | ✗ | out[pos++] = (pix & 0x30) >> 4; | |
117 | ✗ | if (pos < offset) | |
118 | ✗ | out[pos++] = (pix & 0x0C) >> 2; | |
119 | ✗ | if (pos < offset) | |
120 | ✗ | out[pos++] = (pix & 0x03); | |
121 | } | ||
122 | ✗ | left -= 1 + (code + 1); | |
123 | } | ||
124 | } | ||
125 | ✗ | outdata += p->linesize[0]; | |
126 | } | ||
127 | ✗ | return 0; | |
128 | } | ||
129 | |||
130 | ✗ | static int decode_rle_bpp4(AVCodecContext *avctx, AVFrame *p, GetByteContext *gbc) | |
131 | { | ||
132 | ✗ | int offset = avctx->width; | |
133 | ✗ | uint8_t *outdata = p->data[0]; | |
134 | int i, j; | ||
135 | |||
136 | ✗ | for (i = 0; i < avctx->height; i++) { | |
137 | int size, left, code, pix; | ||
138 | ✗ | uint8_t *out = outdata; | |
139 | ✗ | int pos = 0; | |
140 | |||
141 | /* size of packed line */ | ||
142 | ✗ | size = left = bytestream2_get_be16(gbc); | |
143 | ✗ | if (bytestream2_get_bytes_left(gbc) < size) | |
144 | ✗ | return AVERROR_INVALIDDATA; | |
145 | |||
146 | /* decode line */ | ||
147 | ✗ | while (left > 0) { | |
148 | ✗ | code = bytestream2_get_byte(gbc); | |
149 | ✗ | if (code & 0x80 ) { /* run */ | |
150 | ✗ | pix = bytestream2_get_byte(gbc); | |
151 | ✗ | for (j = 0; j < 257 - code; j++) { | |
152 | ✗ | if (pos < offset) | |
153 | ✗ | out[pos++] = (pix & 0xF0) >> 4; | |
154 | ✗ | if (pos < offset) | |
155 | ✗ | out[pos++] = pix & 0xF; | |
156 | } | ||
157 | ✗ | left -= 2; | |
158 | } else { /* copy */ | ||
159 | ✗ | for (j = 0; j < code + 1; j++) { | |
160 | ✗ | pix = bytestream2_get_byte(gbc); | |
161 | ✗ | if (pos < offset) | |
162 | ✗ | out[pos++] = (pix & 0xF0) >> 4; | |
163 | ✗ | if (pos < offset) | |
164 | ✗ | out[pos++] = pix & 0xF; | |
165 | } | ||
166 | ✗ | left -= 1 + (code + 1); | |
167 | } | ||
168 | } | ||
169 | ✗ | outdata += p->linesize[0]; | |
170 | } | ||
171 | ✗ | return 0; | |
172 | } | ||
173 | |||
174 | ✗ | static int decode_rle16(AVCodecContext *avctx, AVFrame *p, GetByteContext *gbc) | |
175 | { | ||
176 | ✗ | int offset = avctx->width; | |
177 | ✗ | uint8_t *outdata = p->data[0]; | |
178 | int i, j; | ||
179 | |||
180 | ✗ | for (i = 0; i < avctx->height; i++) { | |
181 | int size, left, code, pix; | ||
182 | ✗ | uint16_t *out = (uint16_t *)outdata; | |
183 | ✗ | int pos = 0; | |
184 | |||
185 | /* size of packed line */ | ||
186 | ✗ | size = left = bytestream2_get_be16(gbc); | |
187 | ✗ | if (bytestream2_get_bytes_left(gbc) < size) | |
188 | ✗ | return AVERROR_INVALIDDATA; | |
189 | |||
190 | /* decode line */ | ||
191 | ✗ | while (left > 0) { | |
192 | ✗ | code = bytestream2_get_byte(gbc); | |
193 | ✗ | if (code & 0x80 ) { /* run */ | |
194 | ✗ | pix = bytestream2_get_be16(gbc); | |
195 | ✗ | for (j = 0; j < 257 - code; j++) { | |
196 | ✗ | if (pos < offset) { | |
197 | ✗ | out[pos++] = pix; | |
198 | } | ||
199 | } | ||
200 | ✗ | left -= 3; | |
201 | } else { /* copy */ | ||
202 | ✗ | for (j = 0; j < code + 1; j++) { | |
203 | ✗ | if (pos < offset) { | |
204 | ✗ | out[pos++] = bytestream2_get_be16(gbc); | |
205 | } else { | ||
206 | ✗ | bytestream2_skip(gbc, 2); | |
207 | } | ||
208 | } | ||
209 | ✗ | left -= 1 + (code + 1) * 2; | |
210 | } | ||
211 | } | ||
212 | ✗ | outdata += p->linesize[0]; | |
213 | } | ||
214 | ✗ | return 0; | |
215 | } | ||
216 | |||
217 | 15 | static int decode_rle(AVCodecContext *avctx, AVFrame *p, GetByteContext *gbc, | |
218 | int step) | ||
219 | { | ||
220 | int i, j; | ||
221 | 15 | int offset = avctx->width * step; | |
222 | 15 | uint8_t *outdata = p->data[0]; | |
223 | |||
224 |
2/2✓ Branch 0 taken 6368 times.
✓ Branch 1 taken 15 times.
|
6383 | for (i = 0; i < avctx->height; i++) { |
225 | int size, left, code, pix; | ||
226 | 6368 | uint8_t *out = outdata; | |
227 | 6368 | int pos = 0; | |
228 | |||
229 | /* size of packed line */ | ||
230 | 6368 | size = left = bytestream2_get_be16(gbc); | |
231 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 6368 times.
|
6368 | if (bytestream2_get_bytes_left(gbc) < size) |
232 | ✗ | return AVERROR_INVALIDDATA; | |
233 | |||
234 | /* decode line */ | ||
235 |
2/2✓ Branch 0 taken 471569 times.
✓ Branch 1 taken 6368 times.
|
477937 | while (left > 0) { |
236 | 471569 | code = bytestream2_get_byte(gbc); | |
237 |
2/2✓ Branch 0 taken 246815 times.
✓ Branch 1 taken 224754 times.
|
471569 | if (code & 0x80 ) { /* run */ |
238 | 246815 | pix = bytestream2_get_byte(gbc); | |
239 |
2/2✓ Branch 0 taken 1355510 times.
✓ Branch 1 taken 246815 times.
|
1602325 | for (j = 0; j < 257 - code; j++) { |
240 |
1/2✓ Branch 0 taken 1355510 times.
✗ Branch 1 not taken.
|
1355510 | if (pos < offset) |
241 | 1355510 | out[pos] = pix; | |
242 | 1355510 | pos += step; | |
243 |
4/4✓ Branch 0 taken 2605 times.
✓ Branch 1 taken 1352905 times.
✓ Branch 2 taken 384 times.
✓ Branch 3 taken 2221 times.
|
1355510 | if (pos >= offset && step > 1) { |
244 | 384 | pos -= offset; | |
245 | 384 | pos++; | |
246 | } | ||
247 | } | ||
248 | 246815 | left -= 2; | |
249 | } else { /* copy */ | ||
250 |
2/2✓ Branch 0 taken 2736394 times.
✓ Branch 1 taken 224754 times.
|
2961148 | for (j = 0; j < code + 1; j++) { |
251 | 2736394 | pix = bytestream2_get_byte(gbc); | |
252 |
1/2✓ Branch 0 taken 2736394 times.
✗ Branch 1 not taken.
|
2736394 | if (pos < offset) |
253 | 2736394 | out[pos] = pix; | |
254 | 2736394 | pos += step; | |
255 |
3/4✓ Branch 0 taken 4019 times.
✓ Branch 1 taken 2732375 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4019 times.
|
2736394 | if (pos >= offset && step > 1) { |
256 | ✗ | pos -= offset; | |
257 | ✗ | pos++; | |
258 | } | ||
259 | } | ||
260 | 224754 | left -= 2 + code; | |
261 | } | ||
262 | } | ||
263 | 6368 | outdata += p->linesize[0]; | |
264 | } | ||
265 | 15 | return 0; | |
266 | } | ||
267 | |||
268 | 40 | static int check_header(const char *buf, int buf_size) | |
269 | { | ||
270 | unsigned w, h, v0, v1; | ||
271 | |||
272 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
|
40 | if (buf_size < 40) |
273 | ✗ | return 0; | |
274 | |||
275 | 40 | w = AV_RB16(buf+6); | |
276 | 40 | h = AV_RB16(buf+8); | |
277 | 40 | v0 = AV_RB16(buf+10); | |
278 | 40 | v1 = AV_RB16(buf+12); | |
279 | |||
280 |
2/4✓ Branch 0 taken 40 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 40 times.
|
40 | if (!w || !h) |
281 | ✗ | return 0; | |
282 | |||
283 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
|
40 | if (v0 == 0x1101) |
284 | ✗ | return 1; | |
285 |
3/4✓ Branch 0 taken 20 times.
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
|
40 | if (v0 == 0x0011 && v1 == 0x02FF) |
286 | 20 | return 2; | |
287 | 20 | return 0; | |
288 | } | ||
289 | |||
290 | |||
291 | 20 | static int decode_frame(AVCodecContext *avctx, AVFrame *p, | |
292 | int *got_frame, AVPacket *avpkt) | ||
293 | { | ||
294 | GetByteContext gbc; | ||
295 | int colors; | ||
296 | int w, h, ret; | ||
297 | int ver; | ||
298 | |||
299 | 20 | bytestream2_init(&gbc, avpkt->data, avpkt->size); | |
300 |
1/2✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
|
20 | if ( bytestream2_get_bytes_left(&gbc) >= 552 |
301 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 20 times.
|
20 | && check_header(gbc.buffer + 512, bytestream2_get_bytes_left(&gbc) - 512) |
302 | ) | ||
303 | ✗ | bytestream2_skip(&gbc, 512); | |
304 | |||
305 | 20 | ver = check_header(gbc.buffer, bytestream2_get_bytes_left(&gbc)); | |
306 | |||
307 | /* smallest PICT header */ | ||
308 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
|
20 | if (bytestream2_get_bytes_left(&gbc) < 40) { |
309 | ✗ | av_log(avctx, AV_LOG_ERROR, "Frame is too small %d\n", | |
310 | bytestream2_get_bytes_left(&gbc)); | ||
311 | ✗ | return AVERROR_INVALIDDATA; | |
312 | } | ||
313 | |||
314 | 20 | bytestream2_skip(&gbc, 6); | |
315 | 20 | h = bytestream2_get_be16(&gbc); | |
316 | 20 | w = bytestream2_get_be16(&gbc); | |
317 | |||
318 | 20 | ret = ff_set_dimensions(avctx, w, h); | |
319 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
|
20 | if (ret < 0) |
320 | ✗ | return ret; | |
321 | |||
322 | /* version 1 is identified by 0x1101 | ||
323 | * it uses byte-aligned opcodes rather than word-aligned */ | ||
324 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
|
20 | if (ver == 1) { |
325 | ✗ | avpriv_request_sample(avctx, "QuickDraw version 1"); | |
326 | ✗ | return AVERROR_PATCHWELCOME; | |
327 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
|
20 | } else if (ver != 2) { |
328 | ✗ | avpriv_request_sample(avctx, "QuickDraw version unknown (%X)", bytestream2_get_be32(&gbc)); | |
329 | ✗ | return AVERROR_PATCHWELCOME; | |
330 | } | ||
331 | |||
332 | 20 | bytestream2_skip(&gbc, 4+26); | |
333 | |||
334 |
2/2✓ Branch 1 taken 710 times.
✓ Branch 2 taken 5 times.
|
715 | while (bytestream2_get_bytes_left(&gbc) >= 4) { |
335 | int bppcnt, bpp; | ||
336 | int rowbytes, pack_type; | ||
337 | int flags; | ||
338 | 710 | int opcode = bytestream2_get_be16(&gbc); | |
339 | |||
340 |
5/5✓ Branch 0 taken 30 times.
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 655 times.
|
710 | switch(opcode) { |
341 | 30 | case CLIP: | |
342 | 30 | bytestream2_skip(&gbc, 10); | |
343 | 30 | break; | |
344 | 13 | case PACKBITSRECT: | |
345 | case PACKBITSRGN: | ||
346 | 13 | av_log(avctx, AV_LOG_DEBUG, "Parsing Packbit opcode\n"); | |
347 | |||
348 | 13 | flags = bytestream2_get_be16(&gbc) & 0xC000; | |
349 | 13 | bytestream2_skip(&gbc, 28); | |
350 | 13 | bppcnt = bytestream2_get_be16(&gbc); /* cmpCount */ | |
351 | 13 | bpp = bytestream2_get_be16(&gbc); /* cmpSize */ | |
352 | |||
353 | 13 | av_log(avctx, AV_LOG_DEBUG, "bppcount %d bpp %d\n", bppcnt, bpp); | |
354 |
2/4✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
|
13 | if (bppcnt == 1 && bpp == 8) { |
355 | 13 | avctx->pix_fmt = AV_PIX_FMT_PAL8; | |
356 | ✗ | } else if (bppcnt == 1 && (bpp == 4 || bpp == 2)) { | |
357 | ✗ | avctx->pix_fmt = AV_PIX_FMT_PAL8; | |
358 | ✗ | } else if (bppcnt == 3 && bpp == 5) { | |
359 | ✗ | avctx->pix_fmt = AV_PIX_FMT_RGB555; | |
360 | } else { | ||
361 | ✗ | av_log(avctx, AV_LOG_ERROR, | |
362 | "Invalid pixel format (bppcnt %d bpp %d) in Packbit\n", | ||
363 | bppcnt, bpp); | ||
364 | ✗ | return AVERROR_INVALIDDATA; | |
365 | } | ||
366 | |||
367 | /* jump to palette */ | ||
368 | 13 | bytestream2_skip(&gbc, 18); | |
369 | 13 | colors = bytestream2_get_be16(&gbc); | |
370 | |||
371 |
2/4✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
|
13 | if (colors < 0 || colors > 255) { |
372 | ✗ | av_log(avctx, AV_LOG_ERROR, | |
373 | "Error color count - %i(0x%X)\n", colors, colors); | ||
374 | ✗ | return AVERROR_INVALIDDATA; | |
375 | } | ||
376 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
|
13 | if (bytestream2_get_bytes_left(&gbc) < (colors + 1) * 8) { |
377 | ✗ | av_log(avctx, AV_LOG_ERROR, "Palette is too small %d\n", | |
378 | bytestream2_get_bytes_left(&gbc)); | ||
379 | ✗ | return AVERROR_INVALIDDATA; | |
380 | } | ||
381 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
|
13 | if ((ret = ff_get_buffer(avctx, p, 0)) < 0) |
382 | ✗ | return ret; | |
383 | |||
384 | 13 | ret = parse_palette(avctx, &gbc, (uint32_t *)p->data[1], colors, flags & 0x8000); | |
385 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
|
13 | if (ret < 0) |
386 | ✗ | return ret; | |
387 | #if FF_API_PALETTE_HAS_CHANGED | ||
388 | FF_DISABLE_DEPRECATION_WARNINGS | ||
389 | 13 | p->palette_has_changed = 1; | |
390 | FF_ENABLE_DEPRECATION_WARNINGS | ||
391 | #endif | ||
392 | |||
393 | /* jump to image data */ | ||
394 | 13 | bytestream2_skip(&gbc, 18); | |
395 | |||
396 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
|
13 | if (opcode == PACKBITSRGN) { |
397 | ✗ | bytestream2_skip(&gbc, 2 + 8); /* size + rect */ | |
398 | ✗ | avpriv_report_missing_feature(avctx, "Packbit mask region"); | |
399 | } | ||
400 | |||
401 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
|
13 | if (avctx->pix_fmt == AV_PIX_FMT_RGB555) |
402 | ✗ | ret = decode_rle16(avctx, p, &gbc); | |
403 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
|
13 | else if (bpp == 2) |
404 | ✗ | ret = decode_rle_bpp2(avctx, p, &gbc); | |
405 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
|
13 | else if (bpp == 4) |
406 | ✗ | ret = decode_rle_bpp4(avctx, p, &gbc); | |
407 | else | ||
408 | 13 | ret = decode_rle(avctx, p, &gbc, bppcnt); | |
409 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
|
13 | if (ret < 0) |
410 | ✗ | return ret; | |
411 | 13 | *got_frame = 1; | |
412 | 13 | break; | |
413 | 2 | case DIRECTBITSRECT: | |
414 | case DIRECTBITSRGN: | ||
415 | 2 | av_log(avctx, AV_LOG_DEBUG, "Parsing Directbit opcode\n"); | |
416 | |||
417 | 2 | bytestream2_skip(&gbc, 4); | |
418 | 2 | rowbytes = bytestream2_get_be16(&gbc) & 0x3FFF; | |
419 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (rowbytes <= 250) { |
420 | ✗ | avpriv_report_missing_feature(avctx, "Short rowbytes"); | |
421 | ✗ | return AVERROR_PATCHWELCOME; | |
422 | } | ||
423 | |||
424 | 2 | bytestream2_skip(&gbc, 4); | |
425 | 2 | h = bytestream2_get_be16(&gbc); | |
426 | 2 | w = bytestream2_get_be16(&gbc); | |
427 | 2 | bytestream2_skip(&gbc, 2); | |
428 | |||
429 | 2 | ret = ff_set_dimensions(avctx, w, h); | |
430 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (ret < 0) |
431 | ✗ | return ret; | |
432 | |||
433 | 2 | pack_type = bytestream2_get_be16(&gbc); | |
434 | |||
435 | 2 | bytestream2_skip(&gbc, 16); | |
436 | 2 | bppcnt = bytestream2_get_be16(&gbc); /* cmpCount */ | |
437 | 2 | bpp = bytestream2_get_be16(&gbc); /* cmpSize */ | |
438 | |||
439 | 2 | av_log(avctx, AV_LOG_DEBUG, "bppcount %d bpp %d\n", bppcnt, bpp); | |
440 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | if (bppcnt == 3 && bpp == 8) { |
441 | 2 | avctx->pix_fmt = AV_PIX_FMT_RGB24; | |
442 | ✗ | } else if (bppcnt == 3 && bpp == 5 || bppcnt == 2 && bpp == 8) { | |
443 | ✗ | avctx->pix_fmt = AV_PIX_FMT_RGB555; | |
444 | ✗ | } else if (bppcnt == 4 && bpp == 8) { | |
445 | ✗ | avctx->pix_fmt = AV_PIX_FMT_ARGB; | |
446 | } else { | ||
447 | ✗ | av_log(avctx, AV_LOG_ERROR, | |
448 | "Invalid pixel format (bppcnt %d bpp %d) in Directbit\n", | ||
449 | bppcnt, bpp); | ||
450 | ✗ | return AVERROR_INVALIDDATA; | |
451 | } | ||
452 | |||
453 | /* set packing when default is selected */ | ||
454 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (pack_type == 0) |
455 | ✗ | pack_type = bppcnt; | |
456 | |||
457 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
2 | if (pack_type != 3 && pack_type != 4) { |
458 | ✗ | avpriv_request_sample(avctx, "Pack type %d", pack_type); | |
459 | ✗ | return AVERROR_PATCHWELCOME; | |
460 | } | ||
461 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | if (bytestream2_get_bytes_left(&gbc) < 30) |
462 | ✗ | return AVERROR_INVALIDDATA; | |
463 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | if ((ret = ff_get_buffer(avctx, p, 0)) < 0) |
464 | ✗ | return ret; | |
465 | |||
466 | /* jump to data */ | ||
467 | 2 | bytestream2_skip(&gbc, 30); | |
468 | |||
469 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (opcode == DIRECTBITSRGN) { |
470 | ✗ | bytestream2_skip(&gbc, 2 + 8); /* size + rect */ | |
471 | ✗ | avpriv_report_missing_feature(avctx, "DirectBit mask region"); | |
472 | } | ||
473 | |||
474 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (avctx->pix_fmt == AV_PIX_FMT_RGB555) |
475 | ✗ | ret = decode_rle16(avctx, p, &gbc); | |
476 | else | ||
477 | 2 | ret = decode_rle(avctx, p, &gbc, bppcnt); | |
478 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (ret < 0) |
479 | ✗ | return ret; | |
480 | 2 | *got_frame = 1; | |
481 | 2 | break; | |
482 | 10 | case LONGCOMMENT: | |
483 | 10 | bytestream2_get_be16(&gbc); | |
484 | 10 | bytestream2_skip(&gbc, bytestream2_get_be16(&gbc)); | |
485 | 10 | break; | |
486 | 655 | default: | |
487 | 655 | av_log(avctx, AV_LOG_TRACE, "Unknown 0x%04X opcode\n", opcode); | |
488 | 655 | break; | |
489 | } | ||
490 | /* exit the loop when a known pixel block has been found */ | ||
491 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 695 times.
|
710 | if (*got_frame) { |
492 | int eop, trail; | ||
493 | |||
494 | /* re-align to a word */ | ||
495 | 15 | bytestream2_skip(&gbc, bytestream2_get_bytes_left(&gbc) % 2); | |
496 | |||
497 | 15 | eop = bytestream2_get_be16(&gbc); | |
498 | 15 | trail = bytestream2_get_bytes_left(&gbc); | |
499 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
|
15 | if (eop != EOP) |
500 | ✗ | av_log(avctx, AV_LOG_WARNING, | |
501 | "Missing end of picture opcode (found 0x%04X)\n", eop); | ||
502 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
|
15 | if (trail) |
503 | ✗ | av_log(avctx, AV_LOG_WARNING, "Got %d trailing bytes\n", trail); | |
504 | 15 | break; | |
505 | } | ||
506 | } | ||
507 | |||
508 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 5 times.
|
20 | if (*got_frame) { |
509 | 15 | return avpkt->size; | |
510 | } else { | ||
511 | 5 | av_log(avctx, AV_LOG_ERROR, "Frame contained no usable data\n"); | |
512 | |||
513 | 5 | return AVERROR_INVALIDDATA; | |
514 | } | ||
515 | } | ||
516 | |||
517 | const FFCodec ff_qdraw_decoder = { | ||
518 | .p.name = "qdraw", | ||
519 | CODEC_LONG_NAME("Apple QuickDraw"), | ||
520 | .p.type = AVMEDIA_TYPE_VIDEO, | ||
521 | .p.id = AV_CODEC_ID_QDRAW, | ||
522 | .p.capabilities = AV_CODEC_CAP_DR1, | ||
523 | FF_CODEC_DECODE_CB(decode_frame), | ||
524 | }; | ||
525 |