blob: b1b7b5a42f50d061d3f1df5224a1b7cda022bb6a
1 | /* |
2 | * FLI/FLC Animation Video Decoder |
3 | * Copyright (C) 2003, 2004 The FFmpeg project |
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 | * Autodesk Animator FLI/FLC Video Decoder |
25 | * by Mike Melanson (melanson@pcisys.net) |
26 | * for more information on the .fli/.flc file format and all of its many |
27 | * variations, visit: |
28 | * http://www.compuphase.com/flic.htm |
29 | * |
30 | * This decoder outputs PAL8/RGB555/RGB565/BGR24. To use this decoder, be |
31 | * sure that your demuxer sends the FLI file header to the decoder via |
32 | * the extradata chunk in AVCodecContext. The chunk should be 128 bytes |
33 | * large. The only exception is for FLI files from the game "Magic Carpet", |
34 | * in which the header is only 12 bytes. |
35 | */ |
36 | |
37 | #include <stdio.h> |
38 | #include <stdlib.h> |
39 | #include <string.h> |
40 | |
41 | #include "libavutil/intreadwrite.h" |
42 | #include "avcodec.h" |
43 | #include "bytestream.h" |
44 | #include "internal.h" |
45 | #include "mathops.h" |
46 | |
47 | #define FLI_256_COLOR 4 |
48 | #define FLI_DELTA 7 |
49 | #define FLI_COLOR 11 |
50 | #define FLI_LC 12 |
51 | #define FLI_BLACK 13 |
52 | #define FLI_BRUN 15 |
53 | #define FLI_COPY 16 |
54 | #define FLI_MINI 18 |
55 | #define FLI_DTA_BRUN 25 |
56 | #define FLI_DTA_COPY 26 |
57 | #define FLI_DTA_LC 27 |
58 | |
59 | #define FLI_TYPE_CODE (0xAF11) |
60 | #define FLC_FLX_TYPE_CODE (0xAF12) |
61 | #define FLC_DTA_TYPE_CODE (0xAF44) /* Marks an "Extended FLC" comes from Dave's Targa Animator (DTA) */ |
62 | #define FLC_MAGIC_CARPET_SYNTHETIC_TYPE_CODE (0xAF13) |
63 | |
64 | #define CHECK_PIXEL_PTR(n) \ |
65 | if (pixel_ptr + n > pixel_limit) { \ |
66 | av_log (s->avctx, AV_LOG_ERROR, "Invalid pixel_ptr = %d > pixel_limit = %d\n", \ |
67 | pixel_ptr + n, pixel_limit); \ |
68 | return AVERROR_INVALIDDATA; \ |
69 | } \ |
70 | |
71 | typedef struct FlicDecodeContext { |
72 | AVCodecContext *avctx; |
73 | AVFrame *frame; |
74 | |
75 | unsigned int palette[256]; |
76 | int new_palette; |
77 | int fli_type; /* either 0xAF11 or 0xAF12, affects palette resolution */ |
78 | } FlicDecodeContext; |
79 | |
80 | static av_cold int flic_decode_init(AVCodecContext *avctx) |
81 | { |
82 | FlicDecodeContext *s = avctx->priv_data; |
83 | unsigned char *fli_header = (unsigned char *)avctx->extradata; |
84 | int depth; |
85 | |
86 | if (avctx->extradata_size != 0 && |
87 | avctx->extradata_size != 12 && |
88 | avctx->extradata_size != 128 && |
89 | avctx->extradata_size != 256 && |
90 | avctx->extradata_size != 904 && |
91 | avctx->extradata_size != 1024) { |
92 | av_log(avctx, AV_LOG_ERROR, "Unexpected extradata size %d\n", avctx->extradata_size); |
93 | return AVERROR_INVALIDDATA; |
94 | } |
95 | |
96 | s->avctx = avctx; |
97 | |
98 | if (s->avctx->extradata_size == 12) { |
99 | /* special case for magic carpet FLIs */ |
100 | s->fli_type = FLC_MAGIC_CARPET_SYNTHETIC_TYPE_CODE; |
101 | depth = 8; |
102 | } else if (avctx->extradata_size == 1024) { |
103 | uint8_t *ptr = avctx->extradata; |
104 | int i; |
105 | |
106 | for (i = 0; i < 256; i++) { |
107 | s->palette[i] = AV_RL32(ptr); |
108 | ptr += 4; |
109 | } |
110 | depth = 8; |
111 | /* FLI in MOV, see e.g. FFmpeg trac issue #626 */ |
112 | } else if (avctx->extradata_size == 0 || |
113 | avctx->extradata_size == 256 || |
114 | /* see FFmpeg ticket #1234 */ |
115 | avctx->extradata_size == 904) { |
116 | s->fli_type = FLI_TYPE_CODE; |
117 | depth = 8; |
118 | } else { |
119 | s->fli_type = AV_RL16(&fli_header[4]); |
120 | depth = AV_RL16(&fli_header[12]); |
121 | } |
122 | |
123 | if (depth == 0) { |
124 | depth = 8; /* Some FLC generators set depth to zero, when they mean 8Bpp. Fix up here */ |
125 | } |
126 | |
127 | if ((s->fli_type == FLC_FLX_TYPE_CODE) && (depth == 16)) { |
128 | depth = 15; /* Original Autodesk FLX's say the depth is 16Bpp when it is really 15Bpp */ |
129 | } |
130 | |
131 | switch (depth) { |
132 | case 8 : avctx->pix_fmt = AV_PIX_FMT_PAL8; break; |
133 | case 15 : avctx->pix_fmt = AV_PIX_FMT_RGB555; break; |
134 | case 16 : avctx->pix_fmt = AV_PIX_FMT_RGB565; break; |
135 | case 24 : avctx->pix_fmt = AV_PIX_FMT_BGR24; break; |
136 | default : |
137 | av_log(avctx, AV_LOG_ERROR, "Unknown FLC/FLX depth of %d Bpp is unsupported.\n",depth); |
138 | return AVERROR_INVALIDDATA; |
139 | } |
140 | |
141 | s->frame = av_frame_alloc(); |
142 | if (!s->frame) |
143 | return AVERROR(ENOMEM); |
144 | |
145 | s->new_palette = 0; |
146 | |
147 | return 0; |
148 | } |
149 | |
150 | static int flic_decode_frame_8BPP(AVCodecContext *avctx, |
151 | void *data, int *got_frame, |
152 | const uint8_t *buf, int buf_size) |
153 | { |
154 | FlicDecodeContext *s = avctx->priv_data; |
155 | |
156 | GetByteContext g2; |
157 | int pixel_ptr; |
158 | int palette_ptr; |
159 | unsigned char palette_idx1; |
160 | unsigned char palette_idx2; |
161 | |
162 | unsigned int frame_size; |
163 | int num_chunks; |
164 | |
165 | unsigned int chunk_size; |
166 | int chunk_type; |
167 | |
168 | int i, j, ret; |
169 | |
170 | int color_packets; |
171 | int color_changes; |
172 | int color_shift; |
173 | unsigned char r, g, b; |
174 | |
175 | int lines; |
176 | int compressed_lines; |
177 | int starting_line; |
178 | signed short line_packets; |
179 | int y_ptr; |
180 | int byte_run; |
181 | int pixel_skip; |
182 | int pixel_countdown; |
183 | unsigned char *pixels; |
184 | unsigned int pixel_limit; |
185 | |
186 | bytestream2_init(&g2, buf, buf_size); |
187 | |
188 | if ((ret = ff_reget_buffer(avctx, s->frame)) < 0) |
189 | return ret; |
190 | |
191 | pixels = s->frame->data[0]; |
192 | pixel_limit = s->avctx->height * s->frame->linesize[0]; |
193 | if (buf_size < 16 || buf_size > INT_MAX - (3 * 256 + AV_INPUT_BUFFER_PADDING_SIZE)) |
194 | return AVERROR_INVALIDDATA; |
195 | frame_size = bytestream2_get_le32(&g2); |
196 | if (frame_size > buf_size) |
197 | frame_size = buf_size; |
198 | bytestream2_skip(&g2, 2); /* skip the magic number */ |
199 | num_chunks = bytestream2_get_le16(&g2); |
200 | bytestream2_skip(&g2, 8); /* skip padding */ |
201 | |
202 | frame_size -= 16; |
203 | |
204 | /* iterate through the chunks */ |
205 | while ((frame_size >= 6) && (num_chunks > 0) && |
206 | bytestream2_get_bytes_left(&g2) >= 4) { |
207 | int stream_ptr_after_chunk; |
208 | chunk_size = bytestream2_get_le32(&g2); |
209 | if (chunk_size > frame_size) { |
210 | av_log(avctx, AV_LOG_WARNING, |
211 | "Invalid chunk_size = %u > frame_size = %u\n", chunk_size, frame_size); |
212 | chunk_size = frame_size; |
213 | } |
214 | stream_ptr_after_chunk = bytestream2_tell(&g2) - 4 + chunk_size; |
215 | |
216 | chunk_type = bytestream2_get_le16(&g2); |
217 | |
218 | switch (chunk_type) { |
219 | case FLI_256_COLOR: |
220 | case FLI_COLOR: |
221 | /* check special case: If this file is from the Magic Carpet |
222 | * game and uses 6-bit colors even though it reports 256-color |
223 | * chunks in a 0xAF12-type file (fli_type is set to 0xAF13 during |
224 | * initialization) */ |
225 | if ((chunk_type == FLI_256_COLOR) && (s->fli_type != FLC_MAGIC_CARPET_SYNTHETIC_TYPE_CODE)) |
226 | color_shift = 0; |
227 | else |
228 | color_shift = 2; |
229 | /* set up the palette */ |
230 | color_packets = bytestream2_get_le16(&g2); |
231 | palette_ptr = 0; |
232 | for (i = 0; i < color_packets; i++) { |
233 | /* first byte is how many colors to skip */ |
234 | palette_ptr += bytestream2_get_byte(&g2); |
235 | |
236 | /* next byte indicates how many entries to change */ |
237 | color_changes = bytestream2_get_byte(&g2); |
238 | |
239 | /* if there are 0 color changes, there are actually 256 */ |
240 | if (color_changes == 0) |
241 | color_changes = 256; |
242 | |
243 | if (bytestream2_tell(&g2) + color_changes * 3 > stream_ptr_after_chunk) |
244 | break; |
245 | |
246 | for (j = 0; j < color_changes; j++) { |
247 | unsigned int entry; |
248 | |
249 | /* wrap around, for good measure */ |
250 | if ((unsigned)palette_ptr >= 256) |
251 | palette_ptr = 0; |
252 | |
253 | r = bytestream2_get_byte(&g2) << color_shift; |
254 | g = bytestream2_get_byte(&g2) << color_shift; |
255 | b = bytestream2_get_byte(&g2) << color_shift; |
256 | entry = 0xFFU << 24 | r << 16 | g << 8 | b; |
257 | if (color_shift == 2) |
258 | entry |= entry >> 6 & 0x30303; |
259 | if (s->palette[palette_ptr] != entry) |
260 | s->new_palette = 1; |
261 | s->palette[palette_ptr++] = entry; |
262 | } |
263 | } |
264 | break; |
265 | |
266 | case FLI_DELTA: |
267 | y_ptr = 0; |
268 | compressed_lines = bytestream2_get_le16(&g2); |
269 | while (compressed_lines > 0) { |
270 | if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk) |
271 | break; |
272 | line_packets = bytestream2_get_le16(&g2); |
273 | if ((line_packets & 0xC000) == 0xC000) { |
274 | // line skip opcode |
275 | line_packets = -line_packets; |
276 | y_ptr += line_packets * s->frame->linesize[0]; |
277 | } else if ((line_packets & 0xC000) == 0x4000) { |
278 | av_log(avctx, AV_LOG_ERROR, "Undefined opcode (%x) in DELTA_FLI\n", line_packets); |
279 | } else if ((line_packets & 0xC000) == 0x8000) { |
280 | // "last byte" opcode |
281 | pixel_ptr= y_ptr + s->frame->linesize[0] - 1; |
282 | CHECK_PIXEL_PTR(0); |
283 | pixels[pixel_ptr] = line_packets & 0xff; |
284 | } else { |
285 | compressed_lines--; |
286 | pixel_ptr = y_ptr; |
287 | CHECK_PIXEL_PTR(0); |
288 | pixel_countdown = s->avctx->width; |
289 | for (i = 0; i < line_packets; i++) { |
290 | if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk) |
291 | break; |
292 | /* account for the skip bytes */ |
293 | pixel_skip = bytestream2_get_byte(&g2); |
294 | pixel_ptr += pixel_skip; |
295 | pixel_countdown -= pixel_skip; |
296 | byte_run = sign_extend(bytestream2_get_byte(&g2), 8); |
297 | if (byte_run < 0) { |
298 | byte_run = -byte_run; |
299 | palette_idx1 = bytestream2_get_byte(&g2); |
300 | palette_idx2 = bytestream2_get_byte(&g2); |
301 | CHECK_PIXEL_PTR(byte_run * 2); |
302 | for (j = 0; j < byte_run; j++, pixel_countdown -= 2) { |
303 | pixels[pixel_ptr++] = palette_idx1; |
304 | pixels[pixel_ptr++] = palette_idx2; |
305 | } |
306 | } else { |
307 | CHECK_PIXEL_PTR(byte_run * 2); |
308 | if (bytestream2_tell(&g2) + byte_run * 2 > stream_ptr_after_chunk) |
309 | break; |
310 | for (j = 0; j < byte_run * 2; j++, pixel_countdown--) { |
311 | pixels[pixel_ptr++] = bytestream2_get_byte(&g2); |
312 | } |
313 | } |
314 | } |
315 | |
316 | y_ptr += s->frame->linesize[0]; |
317 | } |
318 | } |
319 | break; |
320 | |
321 | case FLI_LC: |
322 | /* line compressed */ |
323 | starting_line = bytestream2_get_le16(&g2); |
324 | y_ptr = 0; |
325 | y_ptr += starting_line * s->frame->linesize[0]; |
326 | |
327 | compressed_lines = bytestream2_get_le16(&g2); |
328 | while (compressed_lines > 0) { |
329 | pixel_ptr = y_ptr; |
330 | CHECK_PIXEL_PTR(0); |
331 | pixel_countdown = s->avctx->width; |
332 | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
333 | break; |
334 | line_packets = bytestream2_get_byte(&g2); |
335 | if (line_packets > 0) { |
336 | for (i = 0; i < line_packets; i++) { |
337 | /* account for the skip bytes */ |
338 | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
339 | break; |
340 | pixel_skip = bytestream2_get_byte(&g2); |
341 | pixel_ptr += pixel_skip; |
342 | pixel_countdown -= pixel_skip; |
343 | byte_run = sign_extend(bytestream2_get_byte(&g2),8); |
344 | if (byte_run > 0) { |
345 | CHECK_PIXEL_PTR(byte_run); |
346 | if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk) |
347 | break; |
348 | for (j = 0; j < byte_run; j++, pixel_countdown--) { |
349 | pixels[pixel_ptr++] = bytestream2_get_byte(&g2); |
350 | } |
351 | } else if (byte_run < 0) { |
352 | byte_run = -byte_run; |
353 | palette_idx1 = bytestream2_get_byte(&g2); |
354 | CHECK_PIXEL_PTR(byte_run); |
355 | for (j = 0; j < byte_run; j++, pixel_countdown--) { |
356 | pixels[pixel_ptr++] = palette_idx1; |
357 | } |
358 | } |
359 | } |
360 | } |
361 | |
362 | y_ptr += s->frame->linesize[0]; |
363 | compressed_lines--; |
364 | } |
365 | break; |
366 | |
367 | case FLI_BLACK: |
368 | /* set the whole frame to color 0 (which is usually black) */ |
369 | memset(pixels, 0, |
370 | s->frame->linesize[0] * s->avctx->height); |
371 | break; |
372 | |
373 | case FLI_BRUN: |
374 | /* Byte run compression: This chunk type only occurs in the first |
375 | * FLI frame and it will update the entire frame. */ |
376 | y_ptr = 0; |
377 | for (lines = 0; lines < s->avctx->height; lines++) { |
378 | pixel_ptr = y_ptr; |
379 | /* disregard the line packets; instead, iterate through all |
380 | * pixels on a row */ |
381 | bytestream2_skip(&g2, 1); |
382 | pixel_countdown = s->avctx->width; |
383 | while (pixel_countdown > 0) { |
384 | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
385 | break; |
386 | byte_run = sign_extend(bytestream2_get_byte(&g2), 8); |
387 | if (!byte_run) { |
388 | av_log(avctx, AV_LOG_ERROR, "Invalid byte run value.\n"); |
389 | return AVERROR_INVALIDDATA; |
390 | } |
391 | |
392 | if (byte_run > 0) { |
393 | palette_idx1 = bytestream2_get_byte(&g2); |
394 | CHECK_PIXEL_PTR(byte_run); |
395 | for (j = 0; j < byte_run; j++) { |
396 | pixels[pixel_ptr++] = palette_idx1; |
397 | pixel_countdown--; |
398 | if (pixel_countdown < 0) |
399 | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n", |
400 | pixel_countdown, lines); |
401 | } |
402 | } else { /* copy bytes if byte_run < 0 */ |
403 | byte_run = -byte_run; |
404 | CHECK_PIXEL_PTR(byte_run); |
405 | if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk) |
406 | break; |
407 | for (j = 0; j < byte_run; j++) { |
408 | pixels[pixel_ptr++] = bytestream2_get_byte(&g2); |
409 | pixel_countdown--; |
410 | if (pixel_countdown < 0) |
411 | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n", |
412 | pixel_countdown, lines); |
413 | } |
414 | } |
415 | } |
416 | |
417 | y_ptr += s->frame->linesize[0]; |
418 | } |
419 | break; |
420 | |
421 | case FLI_COPY: |
422 | /* copy the chunk (uncompressed frame) */ |
423 | if (chunk_size - 6 != FFALIGN(s->avctx->width, 4) * s->avctx->height) { |
424 | av_log(avctx, AV_LOG_ERROR, "In chunk FLI_COPY : source data (%d bytes) " \ |
425 | "has incorrect size, skipping chunk\n", chunk_size - 6); |
426 | bytestream2_skip(&g2, chunk_size - 6); |
427 | } else { |
428 | for (y_ptr = 0; y_ptr < s->frame->linesize[0] * s->avctx->height; |
429 | y_ptr += s->frame->linesize[0]) { |
430 | bytestream2_get_buffer(&g2, &pixels[y_ptr], |
431 | s->avctx->width); |
432 | if (s->avctx->width & 3) |
433 | bytestream2_skip(&g2, 4 - (s->avctx->width & 3)); |
434 | } |
435 | } |
436 | break; |
437 | |
438 | case FLI_MINI: |
439 | /* some sort of a thumbnail? disregard this chunk... */ |
440 | break; |
441 | |
442 | default: |
443 | av_log(avctx, AV_LOG_ERROR, "Unrecognized chunk type: %d\n", chunk_type); |
444 | break; |
445 | } |
446 | |
447 | if (stream_ptr_after_chunk - bytestream2_tell(&g2) > 0) |
448 | bytestream2_skip(&g2, stream_ptr_after_chunk - bytestream2_tell(&g2)); |
449 | |
450 | frame_size -= chunk_size; |
451 | num_chunks--; |
452 | } |
453 | |
454 | /* by the end of the chunk, the stream ptr should equal the frame |
455 | * size (minus 1 or 2, possibly); if it doesn't, issue a warning */ |
456 | if (bytestream2_get_bytes_left(&g2) > 2) |
457 | av_log(avctx, AV_LOG_ERROR, "Processed FLI chunk where chunk size = %d " \ |
458 | "and final chunk ptr = %d\n", buf_size, |
459 | buf_size - bytestream2_get_bytes_left(&g2)); |
460 | |
461 | /* make the palette available on the way out */ |
462 | memcpy(s->frame->data[1], s->palette, AVPALETTE_SIZE); |
463 | if (s->new_palette) { |
464 | s->frame->palette_has_changed = 1; |
465 | s->new_palette = 0; |
466 | } |
467 | |
468 | if ((ret = av_frame_ref(data, s->frame)) < 0) |
469 | return ret; |
470 | |
471 | *got_frame = 1; |
472 | |
473 | return buf_size; |
474 | } |
475 | |
476 | static int flic_decode_frame_15_16BPP(AVCodecContext *avctx, |
477 | void *data, int *got_frame, |
478 | const uint8_t *buf, int buf_size) |
479 | { |
480 | /* Note, the only difference between the 15Bpp and 16Bpp */ |
481 | /* Format is the pixel format, the packets are processed the same. */ |
482 | FlicDecodeContext *s = avctx->priv_data; |
483 | |
484 | GetByteContext g2; |
485 | int pixel_ptr; |
486 | unsigned char palette_idx1; |
487 | |
488 | unsigned int frame_size; |
489 | int num_chunks; |
490 | |
491 | unsigned int chunk_size; |
492 | int chunk_type; |
493 | |
494 | int i, j, ret; |
495 | |
496 | int lines; |
497 | int compressed_lines; |
498 | signed short line_packets; |
499 | int y_ptr; |
500 | int byte_run; |
501 | int pixel_skip; |
502 | int pixel_countdown; |
503 | unsigned char *pixels; |
504 | int pixel; |
505 | unsigned int pixel_limit; |
506 | |
507 | bytestream2_init(&g2, buf, buf_size); |
508 | |
509 | if ((ret = ff_reget_buffer(avctx, s->frame)) < 0) |
510 | return ret; |
511 | |
512 | pixels = s->frame->data[0]; |
513 | pixel_limit = s->avctx->height * s->frame->linesize[0]; |
514 | |
515 | frame_size = bytestream2_get_le32(&g2); |
516 | bytestream2_skip(&g2, 2); /* skip the magic number */ |
517 | num_chunks = bytestream2_get_le16(&g2); |
518 | bytestream2_skip(&g2, 8); /* skip padding */ |
519 | if (frame_size > buf_size) |
520 | frame_size = buf_size; |
521 | |
522 | frame_size -= 16; |
523 | |
524 | /* iterate through the chunks */ |
525 | while ((frame_size > 0) && (num_chunks > 0) && |
526 | bytestream2_get_bytes_left(&g2) >= 4) { |
527 | int stream_ptr_after_chunk; |
528 | chunk_size = bytestream2_get_le32(&g2); |
529 | if (chunk_size > frame_size) { |
530 | av_log(avctx, AV_LOG_WARNING, |
531 | "Invalid chunk_size = %u > frame_size = %u\n", chunk_size, frame_size); |
532 | chunk_size = frame_size; |
533 | } |
534 | stream_ptr_after_chunk = bytestream2_tell(&g2) - 4 + chunk_size; |
535 | |
536 | chunk_type = bytestream2_get_le16(&g2); |
537 | |
538 | |
539 | switch (chunk_type) { |
540 | case FLI_256_COLOR: |
541 | case FLI_COLOR: |
542 | /* For some reason, it seems that non-palettized flics do |
543 | * include one of these chunks in their first frame. |
544 | * Why I do not know, it seems rather extraneous. */ |
545 | ff_dlog(avctx, |
546 | "Unexpected Palette chunk %d in non-palettized FLC\n", |
547 | chunk_type); |
548 | bytestream2_skip(&g2, chunk_size - 6); |
549 | break; |
550 | |
551 | case FLI_DELTA: |
552 | case FLI_DTA_LC: |
553 | y_ptr = 0; |
554 | compressed_lines = bytestream2_get_le16(&g2); |
555 | while (compressed_lines > 0) { |
556 | if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk) |
557 | break; |
558 | line_packets = bytestream2_get_le16(&g2); |
559 | if (line_packets < 0) { |
560 | line_packets = -line_packets; |
561 | y_ptr += line_packets * s->frame->linesize[0]; |
562 | } else { |
563 | compressed_lines--; |
564 | pixel_ptr = y_ptr; |
565 | CHECK_PIXEL_PTR(0); |
566 | pixel_countdown = s->avctx->width; |
567 | for (i = 0; i < line_packets; i++) { |
568 | /* account for the skip bytes */ |
569 | if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk) |
570 | break; |
571 | pixel_skip = bytestream2_get_byte(&g2); |
572 | pixel_ptr += (pixel_skip*2); /* Pixel is 2 bytes wide */ |
573 | pixel_countdown -= pixel_skip; |
574 | byte_run = sign_extend(bytestream2_get_byte(&g2), 8); |
575 | if (byte_run < 0) { |
576 | byte_run = -byte_run; |
577 | pixel = bytestream2_get_le16(&g2); |
578 | CHECK_PIXEL_PTR(2 * byte_run); |
579 | for (j = 0; j < byte_run; j++, pixel_countdown -= 2) { |
580 | *((signed short*)(&pixels[pixel_ptr])) = pixel; |
581 | pixel_ptr += 2; |
582 | } |
583 | } else { |
584 | if (bytestream2_tell(&g2) + 2*byte_run > stream_ptr_after_chunk) |
585 | break; |
586 | CHECK_PIXEL_PTR(2 * byte_run); |
587 | for (j = 0; j < byte_run; j++, pixel_countdown--) { |
588 | *((signed short*)(&pixels[pixel_ptr])) = bytestream2_get_le16(&g2); |
589 | pixel_ptr += 2; |
590 | } |
591 | } |
592 | } |
593 | |
594 | y_ptr += s->frame->linesize[0]; |
595 | } |
596 | } |
597 | break; |
598 | |
599 | case FLI_LC: |
600 | av_log(avctx, AV_LOG_ERROR, "Unexpected FLI_LC chunk in non-palettized FLC\n"); |
601 | bytestream2_skip(&g2, chunk_size - 6); |
602 | break; |
603 | |
604 | case FLI_BLACK: |
605 | /* set the whole frame to 0x0000 which is black in both 15Bpp and 16Bpp modes. */ |
606 | memset(pixels, 0x0000, |
607 | s->frame->linesize[0] * s->avctx->height); |
608 | break; |
609 | |
610 | case FLI_BRUN: |
611 | y_ptr = 0; |
612 | for (lines = 0; lines < s->avctx->height; lines++) { |
613 | pixel_ptr = y_ptr; |
614 | /* disregard the line packets; instead, iterate through all |
615 | * pixels on a row */ |
616 | bytestream2_skip(&g2, 1); |
617 | pixel_countdown = (s->avctx->width * 2); |
618 | |
619 | while (pixel_countdown > 0) { |
620 | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
621 | break; |
622 | byte_run = sign_extend(bytestream2_get_byte(&g2), 8); |
623 | if (byte_run > 0) { |
624 | palette_idx1 = bytestream2_get_byte(&g2); |
625 | CHECK_PIXEL_PTR(byte_run); |
626 | for (j = 0; j < byte_run; j++) { |
627 | pixels[pixel_ptr++] = palette_idx1; |
628 | pixel_countdown--; |
629 | if (pixel_countdown < 0) |
630 | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) (linea%d)\n", |
631 | pixel_countdown, lines); |
632 | } |
633 | } else { /* copy bytes if byte_run < 0 */ |
634 | byte_run = -byte_run; |
635 | if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk) |
636 | break; |
637 | CHECK_PIXEL_PTR(byte_run); |
638 | for (j = 0; j < byte_run; j++) { |
639 | palette_idx1 = bytestream2_get_byte(&g2); |
640 | pixels[pixel_ptr++] = palette_idx1; |
641 | pixel_countdown--; |
642 | if (pixel_countdown < 0) |
643 | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n", |
644 | pixel_countdown, lines); |
645 | } |
646 | } |
647 | } |
648 | |
649 | /* Now FLX is strange, in that it is "byte" as opposed to "pixel" run length compressed. |
650 | * This does not give us any good opportunity to perform word endian conversion |
651 | * during decompression. So if it is required (i.e., this is not a LE target, we do |
652 | * a second pass over the line here, swapping the bytes. |
653 | */ |
654 | #if HAVE_BIGENDIAN |
655 | pixel_ptr = y_ptr; |
656 | pixel_countdown = s->avctx->width; |
657 | while (pixel_countdown > 0) { |
658 | *((signed short*)(&pixels[pixel_ptr])) = AV_RL16(&buf[pixel_ptr]); |
659 | pixel_ptr += 2; |
660 | } |
661 | #endif |
662 | y_ptr += s->frame->linesize[0]; |
663 | } |
664 | break; |
665 | |
666 | case FLI_DTA_BRUN: |
667 | y_ptr = 0; |
668 | for (lines = 0; lines < s->avctx->height; lines++) { |
669 | pixel_ptr = y_ptr; |
670 | /* disregard the line packets; instead, iterate through all |
671 | * pixels on a row */ |
672 | bytestream2_skip(&g2, 1); |
673 | pixel_countdown = s->avctx->width; /* Width is in pixels, not bytes */ |
674 | |
675 | while (pixel_countdown > 0) { |
676 | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
677 | break; |
678 | byte_run = sign_extend(bytestream2_get_byte(&g2), 8); |
679 | if (byte_run > 0) { |
680 | pixel = bytestream2_get_le16(&g2); |
681 | CHECK_PIXEL_PTR(2 * byte_run); |
682 | for (j = 0; j < byte_run; j++) { |
683 | *((signed short*)(&pixels[pixel_ptr])) = pixel; |
684 | pixel_ptr += 2; |
685 | pixel_countdown--; |
686 | if (pixel_countdown < 0) |
687 | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n", |
688 | pixel_countdown); |
689 | } |
690 | } else { /* copy pixels if byte_run < 0 */ |
691 | byte_run = -byte_run; |
692 | if (bytestream2_tell(&g2) + 2 * byte_run > stream_ptr_after_chunk) |
693 | break; |
694 | CHECK_PIXEL_PTR(2 * byte_run); |
695 | for (j = 0; j < byte_run; j++) { |
696 | *((signed short*)(&pixels[pixel_ptr])) = bytestream2_get_le16(&g2); |
697 | pixel_ptr += 2; |
698 | pixel_countdown--; |
699 | if (pixel_countdown < 0) |
700 | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n", |
701 | pixel_countdown); |
702 | } |
703 | } |
704 | } |
705 | |
706 | y_ptr += s->frame->linesize[0]; |
707 | } |
708 | break; |
709 | |
710 | case FLI_COPY: |
711 | case FLI_DTA_COPY: |
712 | /* copy the chunk (uncompressed frame) */ |
713 | if (chunk_size - 6 > (unsigned int)(FFALIGN(s->avctx->width, 2) * s->avctx->height)*2) { |
714 | av_log(avctx, AV_LOG_ERROR, "In chunk FLI_COPY : source data (%d bytes) " \ |
715 | "bigger than image, skipping chunk\n", chunk_size - 6); |
716 | bytestream2_skip(&g2, chunk_size - 6); |
717 | } else { |
718 | |
719 | for (y_ptr = 0; y_ptr < s->frame->linesize[0] * s->avctx->height; |
720 | y_ptr += s->frame->linesize[0]) { |
721 | |
722 | pixel_countdown = s->avctx->width; |
723 | pixel_ptr = 0; |
724 | while (pixel_countdown > 0) { |
725 | *((signed short*)(&pixels[y_ptr + pixel_ptr])) = bytestream2_get_le16(&g2); |
726 | pixel_ptr += 2; |
727 | pixel_countdown--; |
728 | } |
729 | if (s->avctx->width & 1) |
730 | bytestream2_skip(&g2, 2); |
731 | } |
732 | } |
733 | break; |
734 | |
735 | case FLI_MINI: |
736 | /* some sort of a thumbnail? disregard this chunk... */ |
737 | bytestream2_skip(&g2, chunk_size - 6); |
738 | break; |
739 | |
740 | default: |
741 | av_log(avctx, AV_LOG_ERROR, "Unrecognized chunk type: %d\n", chunk_type); |
742 | break; |
743 | } |
744 | |
745 | frame_size -= chunk_size; |
746 | num_chunks--; |
747 | } |
748 | |
749 | /* by the end of the chunk, the stream ptr should equal the frame |
750 | * size (minus 1, possibly); if it doesn't, issue a warning */ |
751 | if ((bytestream2_get_bytes_left(&g2) != 0) && (bytestream2_get_bytes_left(&g2) != 1)) |
752 | av_log(avctx, AV_LOG_ERROR, "Processed FLI chunk where chunk size = %d " \ |
753 | "and final chunk ptr = %d\n", buf_size, bytestream2_tell(&g2)); |
754 | |
755 | if ((ret = av_frame_ref(data, s->frame)) < 0) |
756 | return ret; |
757 | |
758 | *got_frame = 1; |
759 | |
760 | return buf_size; |
761 | } |
762 | |
763 | static int flic_decode_frame_24BPP(AVCodecContext *avctx, |
764 | void *data, int *got_frame, |
765 | const uint8_t *buf, int buf_size) |
766 | { |
767 | FlicDecodeContext *s = avctx->priv_data; |
768 | |
769 | GetByteContext g2; |
770 | int pixel_ptr; |
771 | unsigned char palette_idx1; |
772 | |
773 | unsigned int frame_size; |
774 | int num_chunks; |
775 | |
776 | unsigned int chunk_size; |
777 | int chunk_type; |
778 | |
779 | int i, j, ret; |
780 | |
781 | int lines; |
782 | int compressed_lines; |
783 | signed short line_packets; |
784 | int y_ptr; |
785 | int byte_run; |
786 | int pixel_skip; |
787 | int pixel_countdown; |
788 | unsigned char *pixels; |
789 | int pixel; |
790 | unsigned int pixel_limit; |
791 | |
792 | bytestream2_init(&g2, buf, buf_size); |
793 | |
794 | if ((ret = ff_reget_buffer(avctx, s->frame)) < 0) |
795 | return ret; |
796 | |
797 | pixels = s->frame->data[0]; |
798 | pixel_limit = s->avctx->height * s->frame->linesize[0]; |
799 | |
800 | frame_size = bytestream2_get_le32(&g2); |
801 | bytestream2_skip(&g2, 2); /* skip the magic number */ |
802 | num_chunks = bytestream2_get_le16(&g2); |
803 | bytestream2_skip(&g2, 8); /* skip padding */ |
804 | if (frame_size > buf_size) |
805 | frame_size = buf_size; |
806 | |
807 | frame_size -= 16; |
808 | |
809 | /* iterate through the chunks */ |
810 | while ((frame_size > 0) && (num_chunks > 0) && |
811 | bytestream2_get_bytes_left(&g2) >= 4) { |
812 | int stream_ptr_after_chunk; |
813 | chunk_size = bytestream2_get_le32(&g2); |
814 | if (chunk_size > frame_size) { |
815 | av_log(avctx, AV_LOG_WARNING, |
816 | "Invalid chunk_size = %u > frame_size = %u\n", chunk_size, frame_size); |
817 | chunk_size = frame_size; |
818 | } |
819 | stream_ptr_after_chunk = bytestream2_tell(&g2) - 4 + chunk_size; |
820 | |
821 | chunk_type = bytestream2_get_le16(&g2); |
822 | |
823 | |
824 | switch (chunk_type) { |
825 | case FLI_256_COLOR: |
826 | case FLI_COLOR: |
827 | /* For some reason, it seems that non-palettized flics do |
828 | * include one of these chunks in their first frame. |
829 | * Why I do not know, it seems rather extraneous. */ |
830 | ff_dlog(avctx, |
831 | "Unexpected Palette chunk %d in non-palettized FLC\n", |
832 | chunk_type); |
833 | bytestream2_skip(&g2, chunk_size - 6); |
834 | break; |
835 | |
836 | case FLI_DELTA: |
837 | case FLI_DTA_LC: |
838 | y_ptr = 0; |
839 | compressed_lines = bytestream2_get_le16(&g2); |
840 | while (compressed_lines > 0) { |
841 | if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk) |
842 | break; |
843 | line_packets = bytestream2_get_le16(&g2); |
844 | if (line_packets < 0) { |
845 | line_packets = -line_packets; |
846 | y_ptr += line_packets * s->frame->linesize[0]; |
847 | } else { |
848 | compressed_lines--; |
849 | pixel_ptr = y_ptr; |
850 | CHECK_PIXEL_PTR(0); |
851 | pixel_countdown = s->avctx->width; |
852 | for (i = 0; i < line_packets; i++) { |
853 | /* account for the skip bytes */ |
854 | if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk) |
855 | break; |
856 | pixel_skip = bytestream2_get_byte(&g2); |
857 | pixel_ptr += (pixel_skip*3); /* Pixel is 3 bytes wide */ |
858 | pixel_countdown -= pixel_skip; |
859 | byte_run = sign_extend(bytestream2_get_byte(&g2), 8); |
860 | if (byte_run < 0) { |
861 | byte_run = -byte_run; |
862 | pixel = bytestream2_get_le24(&g2); |
863 | CHECK_PIXEL_PTR(3 * byte_run); |
864 | for (j = 0; j < byte_run; j++, pixel_countdown -= 1) { |
865 | AV_WL24(&pixels[pixel_ptr], pixel); |
866 | pixel_ptr += 3; |
867 | } |
868 | } else { |
869 | if (bytestream2_tell(&g2) + 2*byte_run > stream_ptr_after_chunk) |
870 | break; |
871 | CHECK_PIXEL_PTR(2 * byte_run); |
872 | for (j = 0; j < byte_run; j++, pixel_countdown--) { |
873 | pixel = bytestream2_get_le24(&g2); |
874 | AV_WL24(&pixels[pixel_ptr], pixel); |
875 | pixel_ptr += 3; |
876 | } |
877 | } |
878 | } |
879 | |
880 | y_ptr += s->frame->linesize[0]; |
881 | } |
882 | } |
883 | break; |
884 | |
885 | case FLI_LC: |
886 | av_log(avctx, AV_LOG_ERROR, "Unexpected FLI_LC chunk in non-palettized FLC\n"); |
887 | bytestream2_skip(&g2, chunk_size - 6); |
888 | break; |
889 | |
890 | case FLI_BLACK: |
891 | /* set the whole frame to 0x00 which is black for 24 bit mode. */ |
892 | memset(pixels, 0x00, |
893 | s->frame->linesize[0] * s->avctx->height); |
894 | break; |
895 | |
896 | case FLI_BRUN: |
897 | y_ptr = 0; |
898 | for (lines = 0; lines < s->avctx->height; lines++) { |
899 | pixel_ptr = y_ptr; |
900 | /* disregard the line packets; instead, iterate through all |
901 | * pixels on a row */ |
902 | bytestream2_skip(&g2, 1); |
903 | pixel_countdown = (s->avctx->width * 3); |
904 | |
905 | while (pixel_countdown > 0) { |
906 | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
907 | break; |
908 | byte_run = sign_extend(bytestream2_get_byte(&g2), 8); |
909 | if (byte_run > 0) { |
910 | palette_idx1 = bytestream2_get_byte(&g2); |
911 | CHECK_PIXEL_PTR(byte_run); |
912 | for (j = 0; j < byte_run; j++) { |
913 | pixels[pixel_ptr++] = palette_idx1; |
914 | pixel_countdown--; |
915 | if (pixel_countdown < 0) |
916 | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) (linea%d)\n", |
917 | pixel_countdown, lines); |
918 | } |
919 | } else { /* copy bytes if byte_run < 0 */ |
920 | byte_run = -byte_run; |
921 | if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk) |
922 | break; |
923 | CHECK_PIXEL_PTR(byte_run); |
924 | for (j = 0; j < byte_run; j++) { |
925 | palette_idx1 = bytestream2_get_byte(&g2); |
926 | pixels[pixel_ptr++] = palette_idx1; |
927 | pixel_countdown--; |
928 | if (pixel_countdown < 0) |
929 | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n", |
930 | pixel_countdown, lines); |
931 | } |
932 | } |
933 | } |
934 | |
935 | y_ptr += s->frame->linesize[0]; |
936 | } |
937 | break; |
938 | |
939 | case FLI_DTA_BRUN: |
940 | y_ptr = 0; |
941 | for (lines = 0; lines < s->avctx->height; lines++) { |
942 | pixel_ptr = y_ptr; |
943 | /* disregard the line packets; instead, iterate through all |
944 | * pixels on a row */ |
945 | bytestream2_skip(&g2, 1); |
946 | pixel_countdown = s->avctx->width; /* Width is in pixels, not bytes */ |
947 | |
948 | while (pixel_countdown > 0) { |
949 | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
950 | break; |
951 | byte_run = sign_extend(bytestream2_get_byte(&g2), 8); |
952 | if (byte_run > 0) { |
953 | pixel = bytestream2_get_le24(&g2); |
954 | CHECK_PIXEL_PTR(3 * byte_run); |
955 | for (j = 0; j < byte_run; j++) { |
956 | AV_WL24(pixels + pixel_ptr, pixel); |
957 | pixel_ptr += 3; |
958 | pixel_countdown--; |
959 | if (pixel_countdown < 0) |
960 | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n", |
961 | pixel_countdown); |
962 | } |
963 | } else { /* copy pixels if byte_run < 0 */ |
964 | byte_run = -byte_run; |
965 | if (bytestream2_tell(&g2) + 3 * byte_run > stream_ptr_after_chunk) |
966 | break; |
967 | CHECK_PIXEL_PTR(3 * byte_run); |
968 | for (j = 0; j < byte_run; j++) { |
969 | pixel = bytestream2_get_le24(&g2); |
970 | AV_WL24(pixels + pixel_ptr, pixel); |
971 | pixel_ptr += 3; |
972 | pixel_countdown--; |
973 | if (pixel_countdown < 0) |
974 | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n", |
975 | pixel_countdown); |
976 | } |
977 | } |
978 | } |
979 | |
980 | y_ptr += s->frame->linesize[0]; |
981 | } |
982 | break; |
983 | |
984 | case FLI_COPY: |
985 | case FLI_DTA_COPY: |
986 | /* copy the chunk (uncompressed frame) */ |
987 | if (chunk_size - 6 > (unsigned int)(FFALIGN(s->avctx->width, 2) * s->avctx->height)*3) { |
988 | av_log(avctx, AV_LOG_ERROR, "In chunk FLI_COPY : source data (%d bytes) " \ |
989 | "bigger than image, skipping chunk\n", chunk_size - 6); |
990 | bytestream2_skip(&g2, chunk_size - 6); |
991 | } else { |
992 | for (y_ptr = 0; y_ptr < s->frame->linesize[0] * s->avctx->height; |
993 | y_ptr += s->frame->linesize[0]) { |
994 | |
995 | pixel_countdown = s->avctx->width; |
996 | pixel_ptr = 0; |
997 | while (pixel_countdown > 0) { |
998 | pixel = bytestream2_get_le24(&g2); |
999 | AV_WL24(&pixels[y_ptr + pixel_ptr], pixel); |
1000 | pixel_ptr += 3; |
1001 | pixel_countdown--; |
1002 | } |
1003 | if (s->avctx->width & 1) |
1004 | bytestream2_skip(&g2, 3); |
1005 | } |
1006 | } |
1007 | break; |
1008 | |
1009 | case FLI_MINI: |
1010 | /* some sort of a thumbnail? disregard this chunk... */ |
1011 | bytestream2_skip(&g2, chunk_size - 6); |
1012 | break; |
1013 | |
1014 | default: |
1015 | av_log(avctx, AV_LOG_ERROR, "Unrecognized chunk type: %d\n", chunk_type); |
1016 | break; |
1017 | } |
1018 | |
1019 | frame_size -= chunk_size; |
1020 | num_chunks--; |
1021 | } |
1022 | |
1023 | /* by the end of the chunk, the stream ptr should equal the frame |
1024 | * size (minus 1, possibly); if it doesn't, issue a warning */ |
1025 | if ((bytestream2_get_bytes_left(&g2) != 0) && (bytestream2_get_bytes_left(&g2) != 1)) |
1026 | av_log(avctx, AV_LOG_ERROR, "Processed FLI chunk where chunk size = %d " \ |
1027 | "and final chunk ptr = %d\n", buf_size, bytestream2_tell(&g2)); |
1028 | |
1029 | if ((ret = av_frame_ref(data, s->frame)) < 0) |
1030 | return ret; |
1031 | |
1032 | *got_frame = 1; |
1033 | |
1034 | return buf_size; |
1035 | } |
1036 | |
1037 | static int flic_decode_frame(AVCodecContext *avctx, |
1038 | void *data, int *got_frame, |
1039 | AVPacket *avpkt) |
1040 | { |
1041 | const uint8_t *buf = avpkt->data; |
1042 | int buf_size = avpkt->size; |
1043 | if (avctx->pix_fmt == AV_PIX_FMT_PAL8) { |
1044 | return flic_decode_frame_8BPP(avctx, data, got_frame, |
1045 | buf, buf_size); |
1046 | } else if ((avctx->pix_fmt == AV_PIX_FMT_RGB555) || |
1047 | (avctx->pix_fmt == AV_PIX_FMT_RGB565)) { |
1048 | return flic_decode_frame_15_16BPP(avctx, data, got_frame, |
1049 | buf, buf_size); |
1050 | } else if (avctx->pix_fmt == AV_PIX_FMT_BGR24) { |
1051 | return flic_decode_frame_24BPP(avctx, data, got_frame, |
1052 | buf, buf_size); |
1053 | } |
1054 | |
1055 | /* Should not get here, ever as the pix_fmt is processed */ |
1056 | /* in flic_decode_init and the above if should deal with */ |
1057 | /* the finite set of possibilities allowable by here. */ |
1058 | /* But in case we do, just error out. */ |
1059 | av_log(avctx, AV_LOG_ERROR, "Unknown FLC format, my science cannot explain how this happened.\n"); |
1060 | return AVERROR_BUG; |
1061 | } |
1062 | |
1063 | |
1064 | static av_cold int flic_decode_end(AVCodecContext *avctx) |
1065 | { |
1066 | FlicDecodeContext *s = avctx->priv_data; |
1067 | |
1068 | av_frame_free(&s->frame); |
1069 | |
1070 | return 0; |
1071 | } |
1072 | |
1073 | AVCodec ff_flic_decoder = { |
1074 | .name = "flic", |
1075 | .long_name = NULL_IF_CONFIG_SMALL("Autodesk Animator Flic video"), |
1076 | .type = AVMEDIA_TYPE_VIDEO, |
1077 | .id = AV_CODEC_ID_FLIC, |
1078 | .priv_data_size = sizeof(FlicDecodeContext), |
1079 | .init = flic_decode_init, |
1080 | .close = flic_decode_end, |
1081 | .decode = flic_decode_frame, |
1082 | .capabilities = AV_CODEC_CAP_DR1, |
1083 | }; |
1084 |