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