/src/ffmpeg/libavcodec/flicvideo.c
Line | Count | Source (jump to first uncovered line) |
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 <string.h> |
38 | | |
39 | | #include "libavutil/intreadwrite.h" |
40 | | #include "avcodec.h" |
41 | | #include "bytestream.h" |
42 | | #include "codec_internal.h" |
43 | | #include "decode.h" |
44 | | #include "mathops.h" |
45 | | |
46 | 4.29k | #define FLI_256_COLOR 4 |
47 | 7.45k | #define FLI_DELTA 7 |
48 | 3.42k | #define FLI_COLOR 11 |
49 | 7.57k | #define FLI_LC 12 |
50 | 826 | #define FLI_BLACK 13 |
51 | 4.36k | #define FLI_BRUN 15 |
52 | 2.90k | #define FLI_COPY 16 |
53 | 1.35k | #define FLI_MINI 18 |
54 | 1.84k | #define FLI_DTA_BRUN 25 |
55 | 2.08k | #define FLI_DTA_COPY 26 |
56 | 4.91k | #define FLI_DTA_LC 27 |
57 | | |
58 | 1.06k | #define FLI_TYPE_CODE (0xAF11) |
59 | 2.64k | #define FLC_FLX_TYPE_CODE (0xAF12) |
60 | | #define FLC_DTA_TYPE_CODE (0xAF44) /* Marks an "Extended FLC" comes from Dave's Targa Animator (DTA) */ |
61 | 1.33k | #define FLC_MAGIC_CARPET_SYNTHETIC_TYPE_CODE (0xAF13) |
62 | | |
63 | | static inline int check_pixel_ptr(ptrdiff_t ptr, int n, |
64 | | ptrdiff_t limit, int direction) |
65 | 8.96M | { |
66 | 8.96M | if (( direction && ptr + n > limit) || |
67 | 8.96M | (!direction && ptr + n < limit)) |
68 | 8.31k | return AVERROR_INVALIDDATA; |
69 | 8.95M | return 0; |
70 | 8.96M | } |
71 | | |
72 | 7.30M | #define CHECK_PIXEL_PTR(n) \ |
73 | 7.30M | { \ |
74 | 7.30M | ret = check_pixel_ptr(pixel_ptr, (n), pixel_limit, direction); \ |
75 | 7.30M | if (ret < 0) \ |
76 | 7.30M | return ret; \ |
77 | 7.30M | } |
78 | | |
79 | 30.7k | #define CHECK_Y_PTR() \ |
80 | 30.7k | { \ |
81 | 30.7k | ret = check_pixel_ptr(y_ptr, 0, pixel_limit, direction); \ |
82 | 30.7k | if (ret < 0) \ |
83 | 30.7k | return ret; \ |
84 | 30.7k | } |
85 | | |
86 | | typedef struct FlicDecodeContext { |
87 | | AVCodecContext *avctx; |
88 | | AVFrame *frame; |
89 | | |
90 | | unsigned int palette[256]; |
91 | | int new_palette; |
92 | | int fli_type; /* either 0xAF11 or 0xAF12, affects palette resolution */ |
93 | | } FlicDecodeContext; |
94 | | |
95 | | static av_cold int flic_decode_init(AVCodecContext *avctx) |
96 | 2.70k | { |
97 | 2.70k | FlicDecodeContext *s = avctx->priv_data; |
98 | 2.70k | uint8_t *fli_header = avctx->extradata; |
99 | 2.70k | int depth; |
100 | | |
101 | 2.70k | if (avctx->extradata_size != 0 && |
102 | 2.70k | avctx->extradata_size != 12 && |
103 | 2.70k | avctx->extradata_size != 128 && |
104 | 2.70k | avctx->extradata_size != 256 && |
105 | 2.70k | avctx->extradata_size != 904 && |
106 | 2.70k | avctx->extradata_size != 1024) { |
107 | 55 | av_log(avctx, AV_LOG_ERROR, "Unexpected extradata size %d\n", avctx->extradata_size); |
108 | 55 | return AVERROR_INVALIDDATA; |
109 | 55 | } |
110 | | |
111 | 2.64k | s->avctx = avctx; |
112 | | |
113 | 2.64k | if (s->avctx->extradata_size == 12) { |
114 | | /* special case for magic carpet FLIs */ |
115 | 8 | s->fli_type = FLC_MAGIC_CARPET_SYNTHETIC_TYPE_CODE; |
116 | 8 | depth = 8; |
117 | 2.64k | } else if (avctx->extradata_size == 1024) { |
118 | 2 | uint8_t *ptr = avctx->extradata; |
119 | 2 | int i; |
120 | | |
121 | 514 | for (i = 0; i < 256; i++) { |
122 | 512 | s->palette[i] = AV_RL32(ptr); |
123 | 512 | ptr += 4; |
124 | 512 | } |
125 | 2 | depth = 8; |
126 | | /* FLI in MOV, see e.g. FFmpeg trac issue #626 */ |
127 | 2.63k | } else if (avctx->extradata_size == 0 || |
128 | 2.63k | avctx->extradata_size == 256 || |
129 | | /* see FFmpeg ticket #1234 */ |
130 | 2.63k | avctx->extradata_size == 904) { |
131 | 1.06k | s->fli_type = FLI_TYPE_CODE; |
132 | 1.06k | depth = 8; |
133 | 1.57k | } else { |
134 | 1.57k | s->fli_type = AV_RL16(&fli_header[4]); |
135 | 1.57k | depth = AV_RL16(&fli_header[12]); |
136 | 1.57k | } |
137 | | |
138 | 2.64k | if (depth == 0) { |
139 | 109 | depth = 8; /* Some FLC generators set depth to zero, when they mean 8Bpp. Fix up here */ |
140 | 109 | } |
141 | | |
142 | 2.64k | if ((s->fli_type == FLC_FLX_TYPE_CODE) && (depth == 16)) { |
143 | 1 | depth = 15; /* Original Autodesk FLX's say the depth is 16Bpp when it is really 15Bpp */ |
144 | 1 | } |
145 | | |
146 | 2.64k | switch (depth) { |
147 | 354 | case 1 : avctx->pix_fmt = AV_PIX_FMT_MONOBLACK; break; |
148 | 1.18k | case 8 : avctx->pix_fmt = AV_PIX_FMT_PAL8; break; |
149 | 139 | case 15 : avctx->pix_fmt = AV_PIX_FMT_RGB555; break; |
150 | 419 | case 16 : avctx->pix_fmt = AV_PIX_FMT_RGB565; break; |
151 | 543 | case 24 : avctx->pix_fmt = AV_PIX_FMT_BGR24; break; |
152 | 9 | default : |
153 | 9 | av_log(avctx, AV_LOG_ERROR, "Unknown FLC/FLX depth of %d Bpp is unsupported.\n",depth); |
154 | 9 | return AVERROR_INVALIDDATA; |
155 | 2.64k | } |
156 | | |
157 | 2.63k | s->frame = av_frame_alloc(); |
158 | 2.63k | if (!s->frame) |
159 | 0 | return AVERROR(ENOMEM); |
160 | | |
161 | 2.63k | s->new_palette = 0; |
162 | | |
163 | 2.63k | return 0; |
164 | 2.63k | } |
165 | | |
166 | | static int flic_decode_frame_1BPP(AVCodecContext *avctx, |
167 | | AVFrame *rframe, int *got_frame, |
168 | | const uint8_t *buf, int buf_size) |
169 | 9.03k | { |
170 | 9.03k | FlicDecodeContext *s = avctx->priv_data; |
171 | | |
172 | 9.03k | GetByteContext g2; |
173 | 9.03k | ptrdiff_t pixel_ptr; |
174 | | |
175 | 9.03k | unsigned int frame_size; |
176 | 9.03k | int num_chunks; |
177 | | |
178 | 9.03k | unsigned int chunk_size; |
179 | 9.03k | int chunk_type; |
180 | | |
181 | 9.03k | int i, j, ret, direction; |
182 | | |
183 | 9.03k | int lines; |
184 | 9.03k | int compressed_lines; |
185 | 9.03k | int starting_line; |
186 | 9.03k | int line_packets; |
187 | 9.03k | ptrdiff_t y_ptr; |
188 | 9.03k | int byte_run; |
189 | 9.03k | int pixel_skip; |
190 | 9.03k | int pixel_countdown; |
191 | 9.03k | unsigned char *pixels; |
192 | 9.03k | ptrdiff_t pixel_limit; |
193 | | |
194 | 9.03k | bytestream2_init(&g2, buf, buf_size); |
195 | | |
196 | 9.03k | if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0) |
197 | 217 | return ret; |
198 | | |
199 | 8.81k | direction = s->frame->linesize[0] > 0; |
200 | 8.81k | pixels = s->frame->data[0]; |
201 | 8.81k | pixel_limit = s->avctx->height * s->frame->linesize[0]; |
202 | 8.81k | if (buf_size < 16 || buf_size > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE) |
203 | 714 | return AVERROR_INVALIDDATA; |
204 | 8.10k | frame_size = bytestream2_get_le32(&g2); |
205 | 8.10k | if (frame_size > buf_size) |
206 | 7.83k | frame_size = buf_size; |
207 | 8.10k | bytestream2_skip(&g2, 2); /* skip the magic number */ |
208 | 8.10k | num_chunks = bytestream2_get_le16(&g2); |
209 | 8.10k | bytestream2_skip(&g2, 8); /* skip padding */ |
210 | | |
211 | 8.10k | if (frame_size < 16) |
212 | 255 | return AVERROR_INVALIDDATA; |
213 | | |
214 | 7.84k | frame_size -= 16; |
215 | | |
216 | | /* iterate through the chunks */ |
217 | 11.3k | while ((frame_size >= 6) && (num_chunks > 0) && |
218 | 11.3k | bytestream2_get_bytes_left(&g2) >= 4) { |
219 | 5.64k | int stream_ptr_after_chunk; |
220 | 5.64k | chunk_size = bytestream2_get_le32(&g2); |
221 | 5.64k | if (chunk_size > frame_size) { |
222 | 4.81k | av_log(avctx, AV_LOG_WARNING, |
223 | 4.81k | "Invalid chunk_size = %u > frame_size = %u\n", chunk_size, frame_size); |
224 | 4.81k | chunk_size = frame_size; |
225 | 4.81k | } |
226 | 5.64k | stream_ptr_after_chunk = bytestream2_tell(&g2) - 4 + chunk_size; |
227 | | |
228 | 5.64k | chunk_type = bytestream2_get_le16(&g2); |
229 | | |
230 | 5.64k | switch (chunk_type) { |
231 | 1.29k | case FLI_BRUN: |
232 | | /* Byte run compression: This chunk type only occurs in the first |
233 | | * FLI frame and it will update the entire frame. */ |
234 | 1.29k | y_ptr = 0; |
235 | 2.46M | for (lines = 0; lines < s->avctx->height; lines++) { |
236 | 2.46M | pixel_ptr = y_ptr; |
237 | | /* disregard the line packets; instead, iterate through all |
238 | | * pixels on a row */ |
239 | 2.46M | bytestream2_skip(&g2, 1); |
240 | 2.46M | pixel_countdown = (s->avctx->width + 7) >> 3; |
241 | 2.53M | while (pixel_countdown > 0) { |
242 | 2.48M | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
243 | 2.40M | break; |
244 | 73.2k | byte_run = sign_extend(bytestream2_get_byte(&g2), 8); |
245 | 73.2k | if (!byte_run) { |
246 | 355 | av_log(avctx, AV_LOG_ERROR, "Invalid byte run value.\n"); |
247 | 355 | return AVERROR_INVALIDDATA; |
248 | 355 | } |
249 | | |
250 | 72.8k | if (byte_run > 0) { |
251 | 69.1k | int value = bytestream2_get_byte(&g2); |
252 | 69.1k | CHECK_PIXEL_PTR(byte_run); |
253 | 3.89M | for (j = 0; j < byte_run; j++) { |
254 | 3.82M | pixels[pixel_ptr++] = value; |
255 | 3.82M | pixel_countdown--; |
256 | 3.82M | if (pixel_countdown < 0) |
257 | 2.14M | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n", |
258 | 2.14M | pixel_countdown, lines); |
259 | 3.82M | } |
260 | 68.9k | } else { /* copy bytes if byte_run < 0 */ |
261 | 3.73k | byte_run = -byte_run; |
262 | 3.73k | CHECK_PIXEL_PTR(byte_run); |
263 | 3.51k | if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk) |
264 | 1.13k | break; |
265 | 42.1k | for (j = 0; j < byte_run; j++) { |
266 | 39.7k | pixels[pixel_ptr++] = bytestream2_get_byte(&g2); |
267 | 39.7k | pixel_countdown--; |
268 | 39.7k | if (pixel_countdown < 0) |
269 | 18.6k | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n", |
270 | 18.6k | pixel_countdown, lines); |
271 | 39.7k | } |
272 | 2.37k | } |
273 | 72.8k | } |
274 | | |
275 | 2.45M | y_ptr += s->frame->linesize[0]; |
276 | 2.45M | } |
277 | 509 | break; |
278 | | |
279 | 2.25k | case FLI_LC: |
280 | | /* line compressed */ |
281 | 2.25k | starting_line = bytestream2_get_le16(&g2); |
282 | 2.25k | if (starting_line >= s->avctx->height) |
283 | 252 | return AVERROR_INVALIDDATA; |
284 | 2.00k | y_ptr = 0; |
285 | 2.00k | y_ptr += starting_line * s->frame->linesize[0]; |
286 | | |
287 | 2.00k | compressed_lines = bytestream2_get_le16(&g2); |
288 | 180k | while (compressed_lines > 0) { |
289 | 179k | pixel_ptr = y_ptr; |
290 | 179k | CHECK_PIXEL_PTR(0); |
291 | 179k | pixel_countdown = (s->avctx->width + 7) >> 3; |
292 | 179k | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
293 | 724 | break; |
294 | 178k | line_packets = bytestream2_get_byte(&g2); |
295 | 178k | if (line_packets > 0) { |
296 | 1.19M | for (i = 0; i < line_packets; i++) { |
297 | | /* account for the skip bytes */ |
298 | 1.17M | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
299 | 761 | break; |
300 | 1.17M | pixel_skip = bytestream2_get_byte(&g2); |
301 | 1.17M | pixel_ptr += pixel_skip; |
302 | 1.17M | pixel_countdown -= pixel_skip; |
303 | 1.17M | byte_run = sign_extend(bytestream2_get_byte(&g2),8); |
304 | 1.17M | if (byte_run > 0) { |
305 | 247k | CHECK_PIXEL_PTR(byte_run); |
306 | 247k | if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk) |
307 | 1.71k | break; |
308 | 5.36M | for (j = 0; j < byte_run; j++, pixel_countdown--) { |
309 | 5.11M | pixels[pixel_ptr++] = bytestream2_get_byte(&g2); |
310 | 5.11M | } |
311 | 924k | } else if (byte_run < 0) { |
312 | 328k | int value = bytestream2_get_byte(&g2); |
313 | 328k | byte_run = -byte_run; |
314 | 328k | CHECK_PIXEL_PTR(byte_run); |
315 | 16.6M | for (j = 0; j < byte_run; j++, pixel_countdown--) { |
316 | 16.3M | pixels[pixel_ptr++] = value; |
317 | 16.3M | } |
318 | 327k | } |
319 | 1.17M | } |
320 | 26.3k | } |
321 | | |
322 | 178k | y_ptr += s->frame->linesize[0]; |
323 | 178k | compressed_lines--; |
324 | 178k | } |
325 | 1.15k | break; |
326 | | |
327 | 2.09k | default: |
328 | 2.09k | av_log(avctx, AV_LOG_ERROR, "Unrecognized chunk type: %d\n", chunk_type); |
329 | 2.09k | break; |
330 | 5.64k | } |
331 | | |
332 | 3.76k | if (stream_ptr_after_chunk - bytestream2_tell(&g2) >= 0) { |
333 | 3.47k | bytestream2_skip(&g2, stream_ptr_after_chunk - bytestream2_tell(&g2)); |
334 | 3.47k | } else { |
335 | 289 | av_log(avctx, AV_LOG_ERROR, "Chunk overread\n"); |
336 | 289 | break; |
337 | 289 | } |
338 | | |
339 | 3.47k | frame_size -= chunk_size; |
340 | 3.47k | num_chunks--; |
341 | 3.47k | } |
342 | | |
343 | | /* by the end of the chunk, the stream ptr should equal the frame |
344 | | * size (minus 1 or 2, possibly); if it doesn't, issue a warning */ |
345 | 5.96k | if (bytestream2_get_bytes_left(&g2) > 2) |
346 | 2.01k | av_log(avctx, AV_LOG_ERROR, "Processed FLI chunk where chunk size = %d " \ |
347 | 2.01k | "and final chunk ptr = %d\n", buf_size, |
348 | 2.01k | buf_size - bytestream2_get_bytes_left(&g2)); |
349 | | |
350 | 5.96k | if ((ret = av_frame_ref(rframe, s->frame)) < 0) |
351 | 0 | return ret; |
352 | | |
353 | 5.96k | *got_frame = 1; |
354 | | |
355 | 5.96k | return buf_size; |
356 | 5.96k | } |
357 | | |
358 | | static int flic_decode_frame_8BPP(AVCodecContext *avctx, |
359 | | AVFrame *rframe, int *got_frame, |
360 | | const uint8_t *buf, int buf_size) |
361 | 113k | { |
362 | 113k | FlicDecodeContext *s = avctx->priv_data; |
363 | | |
364 | 113k | GetByteContext g2; |
365 | 113k | ptrdiff_t pixel_ptr; |
366 | 113k | int palette_ptr; |
367 | 113k | unsigned char palette_idx1; |
368 | 113k | unsigned char palette_idx2; |
369 | | |
370 | 113k | unsigned int frame_size; |
371 | 113k | int num_chunks; |
372 | | |
373 | 113k | unsigned int chunk_size; |
374 | 113k | int chunk_type; |
375 | | |
376 | 113k | int i, j, ret, direction; |
377 | | |
378 | 113k | int color_packets; |
379 | 113k | int color_changes; |
380 | 113k | int color_shift; |
381 | 113k | unsigned char r, g, b; |
382 | | |
383 | 113k | int lines; |
384 | 113k | int compressed_lines; |
385 | 113k | int starting_line; |
386 | 113k | int line_packets; |
387 | 113k | ptrdiff_t y_ptr; |
388 | 113k | int byte_run; |
389 | 113k | int pixel_skip; |
390 | 113k | int pixel_countdown; |
391 | 113k | unsigned char *pixels; |
392 | 113k | ptrdiff_t pixel_limit; |
393 | | |
394 | 113k | bytestream2_init(&g2, buf, buf_size); |
395 | | |
396 | 113k | if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0) |
397 | 4.72k | return ret; |
398 | | |
399 | 109k | direction = s->frame->linesize[0] > 0; |
400 | 109k | pixels = s->frame->data[0]; |
401 | 109k | pixel_limit = s->avctx->height * s->frame->linesize[0]; |
402 | 109k | if (buf_size < 16 || buf_size > INT_MAX - (3 * 256 + AV_INPUT_BUFFER_PADDING_SIZE)) |
403 | 4.00k | return AVERROR_INVALIDDATA; |
404 | 105k | frame_size = bytestream2_get_le32(&g2); |
405 | 105k | if (frame_size > buf_size) |
406 | 104k | frame_size = buf_size; |
407 | 105k | bytestream2_skip(&g2, 2); /* skip the magic number */ |
408 | 105k | num_chunks = bytestream2_get_le16(&g2); |
409 | 105k | bytestream2_skip(&g2, 8); /* skip padding */ |
410 | | |
411 | 105k | if (frame_size < 16) |
412 | 269 | return AVERROR_INVALIDDATA; |
413 | | |
414 | 104k | frame_size -= 16; |
415 | | |
416 | | /* iterate through the chunks */ |
417 | 117k | while ((frame_size >= 6) && (num_chunks > 0) && |
418 | 117k | bytestream2_get_bytes_left(&g2) >= 4) { |
419 | 17.0k | int stream_ptr_after_chunk; |
420 | 17.0k | chunk_size = bytestream2_get_le32(&g2); |
421 | 17.0k | if (chunk_size > frame_size) { |
422 | 15.0k | av_log(avctx, AV_LOG_WARNING, |
423 | 15.0k | "Invalid chunk_size = %u > frame_size = %u\n", chunk_size, frame_size); |
424 | 15.0k | chunk_size = frame_size; |
425 | 15.0k | } |
426 | 17.0k | stream_ptr_after_chunk = bytestream2_tell(&g2) - 4 + chunk_size; |
427 | | |
428 | 17.0k | chunk_type = bytestream2_get_le16(&g2); |
429 | | |
430 | 17.0k | switch (chunk_type) { |
431 | 1.33k | case FLI_256_COLOR: |
432 | 1.98k | case FLI_COLOR: |
433 | | /* check special case: If this file is from the Magic Carpet |
434 | | * game and uses 6-bit colors even though it reports 256-color |
435 | | * chunks in a 0xAF12-type file (fli_type is set to 0xAF13 during |
436 | | * initialization) */ |
437 | 1.98k | if ((chunk_type == FLI_256_COLOR) && (s->fli_type != FLC_MAGIC_CARPET_SYNTHETIC_TYPE_CODE)) |
438 | 1.13k | color_shift = 0; |
439 | 855 | else |
440 | 855 | color_shift = 2; |
441 | | /* set up the palette */ |
442 | 1.98k | color_packets = bytestream2_get_le16(&g2); |
443 | 1.98k | palette_ptr = 0; |
444 | 67.9k | for (i = 0; i < color_packets; i++) { |
445 | | /* first byte is how many colors to skip */ |
446 | 67.0k | palette_ptr += bytestream2_get_byte(&g2); |
447 | | |
448 | | /* next byte indicates how many entries to change */ |
449 | 67.0k | color_changes = bytestream2_get_byte(&g2); |
450 | | |
451 | | /* if there are 0 color changes, there are actually 256 */ |
452 | 67.0k | if (color_changes == 0) |
453 | 5.68k | color_changes = 256; |
454 | | |
455 | 67.0k | if (bytestream2_tell(&g2) + color_changes * 3 > stream_ptr_after_chunk) |
456 | 1.05k | break; |
457 | | |
458 | 2.14M | for (j = 0; j < color_changes; j++) { |
459 | 2.07M | unsigned int entry; |
460 | | |
461 | | /* wrap around, for good measure */ |
462 | 2.07M | if ((unsigned)palette_ptr >= 256) |
463 | 9.99k | palette_ptr = 0; |
464 | | |
465 | 2.07M | r = bytestream2_get_byte(&g2) << color_shift; |
466 | 2.07M | g = bytestream2_get_byte(&g2) << color_shift; |
467 | 2.07M | b = bytestream2_get_byte(&g2) << color_shift; |
468 | 2.07M | entry = 0xFFU << 24 | r << 16 | g << 8 | b; |
469 | 2.07M | if (color_shift == 2) |
470 | 1.99k | entry |= entry >> 6 & 0x30303; |
471 | 2.07M | if (s->palette[palette_ptr] != entry) |
472 | 1.85M | s->new_palette = 1; |
473 | 2.07M | s->palette[palette_ptr++] = entry; |
474 | 2.07M | } |
475 | 65.9k | } |
476 | 1.98k | break; |
477 | | |
478 | 3.24k | case FLI_DELTA: |
479 | 3.24k | y_ptr = 0; |
480 | 3.24k | compressed_lines = bytestream2_get_le16(&g2); |
481 | 20.3k | while (compressed_lines > 0) { |
482 | 19.7k | if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk) |
483 | 1.22k | break; |
484 | 18.5k | CHECK_Y_PTR() |
485 | 18.1k | line_packets = sign_extend(bytestream2_get_le16(&g2), 16); |
486 | 18.1k | if ((line_packets & 0xC000) == 0xC000) { |
487 | | // line skip opcode |
488 | 3.96k | line_packets = -line_packets; |
489 | 3.96k | if (line_packets > s->avctx->height) |
490 | 364 | return AVERROR_INVALIDDATA; |
491 | 3.60k | y_ptr += line_packets * s->frame->linesize[0]; |
492 | 14.1k | } else if ((line_packets & 0xC000) == 0x4000) { |
493 | 1.68k | av_log(avctx, AV_LOG_ERROR, "Undefined opcode (%x) in DELTA_FLI\n", line_packets); |
494 | 12.4k | } else if ((line_packets & 0xC000) == 0x8000) { |
495 | | // "last byte" opcode |
496 | 1.26k | pixel_ptr= y_ptr + s->frame->linesize[0] - 1; |
497 | 1.26k | CHECK_PIXEL_PTR(0); |
498 | 1.04k | pixels[pixel_ptr] = line_packets & 0xff; |
499 | 11.2k | } else { |
500 | 11.2k | compressed_lines--; |
501 | 11.2k | pixel_ptr = y_ptr; |
502 | 11.2k | CHECK_PIXEL_PTR(0); |
503 | 11.2k | pixel_countdown = s->avctx->width; |
504 | 850k | for (i = 0; i < line_packets; i++) { |
505 | 842k | if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk) |
506 | 948 | break; |
507 | | /* account for the skip bytes */ |
508 | 841k | pixel_skip = bytestream2_get_byte(&g2); |
509 | 841k | pixel_ptr += pixel_skip; |
510 | 841k | pixel_countdown -= pixel_skip; |
511 | 841k | byte_run = sign_extend(bytestream2_get_byte(&g2), 8); |
512 | 841k | if (byte_run < 0) { |
513 | 230k | byte_run = -byte_run; |
514 | 230k | palette_idx1 = bytestream2_get_byte(&g2); |
515 | 230k | palette_idx2 = bytestream2_get_byte(&g2); |
516 | 230k | CHECK_PIXEL_PTR(byte_run * 2); |
517 | 5.87M | for (j = 0; j < byte_run; j++, pixel_countdown -= 2) { |
518 | 5.64M | pixels[pixel_ptr++] = palette_idx1; |
519 | 5.64M | pixels[pixel_ptr++] = palette_idx2; |
520 | 5.64M | } |
521 | 611k | } else { |
522 | 611k | CHECK_PIXEL_PTR(byte_run * 2); |
523 | 610k | if (bytestream2_tell(&g2) + byte_run * 2 > stream_ptr_after_chunk) |
524 | 1.39k | break; |
525 | 5.12M | for (j = 0; j < byte_run * 2; j++, pixel_countdown--) { |
526 | 4.51M | pixels[pixel_ptr++] = bytestream2_get_byte(&g2); |
527 | 4.51M | } |
528 | 609k | } |
529 | 841k | } |
530 | | |
531 | 10.7k | y_ptr += s->frame->linesize[0]; |
532 | 10.7k | } |
533 | 18.1k | } |
534 | 1.80k | break; |
535 | | |
536 | 4.09k | case FLI_LC: |
537 | | /* line compressed */ |
538 | 4.09k | starting_line = bytestream2_get_le16(&g2); |
539 | 4.09k | if (starting_line >= s->avctx->height) |
540 | 256 | return AVERROR_INVALIDDATA; |
541 | 3.84k | y_ptr = 0; |
542 | 3.84k | y_ptr += starting_line * s->frame->linesize[0]; |
543 | | |
544 | 3.84k | compressed_lines = bytestream2_get_le16(&g2); |
545 | 389k | while (compressed_lines > 0) { |
546 | 388k | pixel_ptr = y_ptr; |
547 | 388k | CHECK_PIXEL_PTR(0); |
548 | 388k | pixel_countdown = s->avctx->width; |
549 | 388k | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
550 | 2.10k | break; |
551 | 386k | line_packets = bytestream2_get_byte(&g2); |
552 | 386k | if (line_packets > 0) { |
553 | 1.07M | for (i = 0; i < line_packets; i++) { |
554 | | /* account for the skip bytes */ |
555 | 1.03M | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
556 | 2.06k | break; |
557 | 1.02M | pixel_skip = bytestream2_get_byte(&g2); |
558 | 1.02M | pixel_ptr += pixel_skip; |
559 | 1.02M | pixel_countdown -= pixel_skip; |
560 | 1.02M | byte_run = sign_extend(bytestream2_get_byte(&g2),8); |
561 | 1.02M | if (byte_run > 0) { |
562 | 245k | CHECK_PIXEL_PTR(byte_run); |
563 | 244k | if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk) |
564 | 4.29k | break; |
565 | 4.08M | for (j = 0; j < byte_run; j++, pixel_countdown--) { |
566 | 3.84M | pixels[pixel_ptr++] = bytestream2_get_byte(&g2); |
567 | 3.84M | } |
568 | 783k | } else if (byte_run < 0) { |
569 | 251k | byte_run = -byte_run; |
570 | 251k | palette_idx1 = bytestream2_get_byte(&g2); |
571 | 251k | CHECK_PIXEL_PTR(byte_run); |
572 | 12.3M | for (j = 0; j < byte_run; j++, pixel_countdown--) { |
573 | 12.0M | pixels[pixel_ptr++] = palette_idx1; |
574 | 12.0M | } |
575 | 250k | } |
576 | 1.02M | } |
577 | 49.6k | } |
578 | | |
579 | 385k | y_ptr += s->frame->linesize[0]; |
580 | 385k | compressed_lines--; |
581 | 385k | } |
582 | 2.60k | break; |
583 | | |
584 | 2.60k | case FLI_BLACK: |
585 | | /* set the whole frame to color 0 (which is usually black) */ |
586 | 1.78M | for (int y = 0; y < s->avctx->height; y++) |
587 | 1.78M | memset(pixels + y * s->frame->linesize[0], 0, s->avctx->width); |
588 | 322 | break; |
589 | | |
590 | 1.36k | case FLI_BRUN: |
591 | | /* Byte run compression: This chunk type only occurs in the first |
592 | | * FLI frame and it will update the entire frame. */ |
593 | 1.36k | y_ptr = 0; |
594 | 1.86M | for (lines = 0; lines < s->avctx->height; lines++) { |
595 | 1.86M | pixel_ptr = y_ptr; |
596 | | /* disregard the line packets; instead, iterate through all |
597 | | * pixels on a row */ |
598 | 1.86M | bytestream2_skip(&g2, 1); |
599 | 1.86M | pixel_countdown = s->avctx->width; |
600 | 3.21M | while (pixel_countdown > 0) { |
601 | 2.99M | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
602 | 1.64M | break; |
603 | 1.35M | byte_run = sign_extend(bytestream2_get_byte(&g2), 8); |
604 | 1.35M | if (!byte_run) { |
605 | 364 | av_log(avctx, AV_LOG_ERROR, "Invalid byte run value.\n"); |
606 | 364 | return AVERROR_INVALIDDATA; |
607 | 364 | } |
608 | | |
609 | 1.35M | if (byte_run > 0) { |
610 | 1.34M | palette_idx1 = bytestream2_get_byte(&g2); |
611 | 1.34M | CHECK_PIXEL_PTR(byte_run); |
612 | 37.4M | for (j = 0; j < byte_run; j++) { |
613 | 36.0M | pixels[pixel_ptr++] = palette_idx1; |
614 | 36.0M | pixel_countdown--; |
615 | 36.0M | if (pixel_countdown < 0) |
616 | 8.00M | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n", |
617 | 8.00M | pixel_countdown, lines); |
618 | 36.0M | } |
619 | 1.34M | } else { /* copy bytes if byte_run < 0 */ |
620 | 7.80k | byte_run = -byte_run; |
621 | 7.80k | CHECK_PIXEL_PTR(byte_run); |
622 | 7.59k | if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk) |
623 | 1.30k | break; |
624 | 63.5k | for (j = 0; j < byte_run; j++) { |
625 | 57.2k | pixels[pixel_ptr++] = bytestream2_get_byte(&g2); |
626 | 57.2k | pixel_countdown--; |
627 | 57.2k | if (pixel_countdown < 0) |
628 | 11.4k | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n", |
629 | 11.4k | pixel_countdown, lines); |
630 | 57.2k | } |
631 | 6.28k | } |
632 | 1.35M | } |
633 | | |
634 | 1.86M | y_ptr += s->frame->linesize[0]; |
635 | 1.86M | } |
636 | 556 | break; |
637 | | |
638 | 1.28k | case FLI_COPY: |
639 | | /* copy the chunk (uncompressed frame) */ |
640 | 1.28k | if (chunk_size - 6 != FFALIGN(s->avctx->width, 4) * s->avctx->height) { |
641 | 671 | av_log(avctx, AV_LOG_ERROR, "In chunk FLI_COPY : source data (%d bytes) " \ |
642 | 671 | "has incorrect size, skipping chunk\n", chunk_size - 6); |
643 | 671 | bytestream2_skip(&g2, chunk_size - 6); |
644 | 671 | } else { |
645 | 3.72k | for (y_ptr = 0; check_pixel_ptr(y_ptr, s->avctx->width, pixel_limit, direction) == 0; |
646 | 3.11k | y_ptr += s->frame->linesize[0]) { |
647 | 3.11k | bytestream2_get_buffer(&g2, &pixels[y_ptr], |
648 | 3.11k | s->avctx->width); |
649 | 3.11k | if (s->avctx->width & 3) |
650 | 2.16k | bytestream2_skip(&g2, 4 - (s->avctx->width & 3)); |
651 | 3.11k | } |
652 | 613 | } |
653 | 1.28k | break; |
654 | | |
655 | 250 | case FLI_MINI: |
656 | | /* some sort of a thumbnail? disregard this chunk... */ |
657 | 250 | break; |
658 | | |
659 | 4.52k | default: |
660 | 4.52k | av_log(avctx, AV_LOG_ERROR, "Unrecognized chunk type: %d\n", chunk_type); |
661 | 4.52k | break; |
662 | 17.0k | } |
663 | | |
664 | 13.3k | if (stream_ptr_after_chunk - bytestream2_tell(&g2) >= 0) { |
665 | 12.2k | bytestream2_skip(&g2, stream_ptr_after_chunk - bytestream2_tell(&g2)); |
666 | 12.2k | } else { |
667 | 1.10k | av_log(avctx, AV_LOG_ERROR, "Chunk overread\n"); |
668 | 1.10k | break; |
669 | 1.10k | } |
670 | | |
671 | 12.2k | frame_size -= chunk_size; |
672 | 12.2k | num_chunks--; |
673 | 12.2k | } |
674 | | |
675 | | /* by the end of the chunk, the stream ptr should equal the frame |
676 | | * size (minus 1 or 2, possibly); if it doesn't, issue a warning */ |
677 | 101k | if (bytestream2_get_bytes_left(&g2) > 2) |
678 | 23.9k | av_log(avctx, AV_LOG_ERROR, "Processed FLI chunk where chunk size = %d " \ |
679 | 23.9k | "and final chunk ptr = %d\n", buf_size, |
680 | 23.9k | buf_size - bytestream2_get_bytes_left(&g2)); |
681 | | |
682 | | /* make the palette available on the way out */ |
683 | 101k | memcpy(s->frame->data[1], s->palette, AVPALETTE_SIZE); |
684 | 101k | if (s->new_palette) { |
685 | 503 | #if FF_API_PALETTE_HAS_CHANGED |
686 | 503 | FF_DISABLE_DEPRECATION_WARNINGS |
687 | 503 | s->frame->palette_has_changed = 1; |
688 | 503 | FF_ENABLE_DEPRECATION_WARNINGS |
689 | 503 | #endif |
690 | 503 | s->new_palette = 0; |
691 | 503 | } |
692 | | |
693 | 101k | if ((ret = av_frame_ref(rframe, s->frame)) < 0) |
694 | 0 | return ret; |
695 | | |
696 | 101k | *got_frame = 1; |
697 | | |
698 | 101k | return buf_size; |
699 | 101k | } |
700 | | |
701 | | static int flic_decode_frame_15_16BPP(AVCodecContext *avctx, |
702 | | AVFrame *rframe, int *got_frame, |
703 | | const uint8_t *buf, int buf_size) |
704 | 12.2k | { |
705 | | /* Note, the only difference between the 15Bpp and 16Bpp */ |
706 | | /* Format is the pixel format, the packets are processed the same. */ |
707 | 12.2k | FlicDecodeContext *s = avctx->priv_data; |
708 | | |
709 | 12.2k | GetByteContext g2; |
710 | 12.2k | ptrdiff_t pixel_ptr; |
711 | 12.2k | unsigned char palette_idx1; |
712 | | |
713 | 12.2k | unsigned int frame_size; |
714 | 12.2k | int num_chunks; |
715 | | |
716 | 12.2k | unsigned int chunk_size; |
717 | 12.2k | int chunk_type; |
718 | | |
719 | 12.2k | int i, j, ret, direction; |
720 | | |
721 | 12.2k | int lines; |
722 | 12.2k | int compressed_lines; |
723 | 12.2k | int line_packets; |
724 | 12.2k | ptrdiff_t y_ptr; |
725 | 12.2k | int byte_run; |
726 | 12.2k | int pixel_skip; |
727 | 12.2k | int pixel_countdown; |
728 | 12.2k | unsigned char *pixels; |
729 | 12.2k | int pixel; |
730 | 12.2k | ptrdiff_t pixel_limit; |
731 | | |
732 | 12.2k | bytestream2_init(&g2, buf, buf_size); |
733 | | |
734 | 12.2k | if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0) |
735 | 335 | return ret; |
736 | | |
737 | 11.8k | direction = s->frame->linesize[0] > 0; |
738 | 11.8k | pixels = s->frame->data[0]; |
739 | 11.8k | pixel_limit = s->avctx->height * s->frame->linesize[0]; |
740 | | |
741 | 11.8k | frame_size = bytestream2_get_le32(&g2); |
742 | 11.8k | bytestream2_skip(&g2, 2); /* skip the magic number */ |
743 | 11.8k | num_chunks = bytestream2_get_le16(&g2); |
744 | 11.8k | bytestream2_skip(&g2, 8); /* skip padding */ |
745 | 11.8k | if (frame_size > buf_size) |
746 | 10.7k | frame_size = buf_size; |
747 | | |
748 | 11.8k | if (frame_size < 16) |
749 | 1.15k | return AVERROR_INVALIDDATA; |
750 | 10.7k | frame_size -= 16; |
751 | | |
752 | | /* iterate through the chunks */ |
753 | 16.9k | while ((frame_size > 0) && (num_chunks > 0) && |
754 | 16.9k | bytestream2_get_bytes_left(&g2) >= 4) { |
755 | 9.56k | int stream_ptr_after_chunk; |
756 | 9.56k | chunk_size = bytestream2_get_le32(&g2); |
757 | 9.56k | if (chunk_size > frame_size) { |
758 | 7.13k | av_log(avctx, AV_LOG_WARNING, |
759 | 7.13k | "Invalid chunk_size = %u > frame_size = %u\n", chunk_size, frame_size); |
760 | 7.13k | chunk_size = frame_size; |
761 | 7.13k | } |
762 | 9.56k | stream_ptr_after_chunk = bytestream2_tell(&g2) - 4 + chunk_size; |
763 | | |
764 | 9.56k | chunk_type = bytestream2_get_le16(&g2); |
765 | | |
766 | | |
767 | 9.56k | switch (chunk_type) { |
768 | 497 | case FLI_256_COLOR: |
769 | 727 | case FLI_COLOR: |
770 | | /* For some reason, it seems that non-palettized flics do |
771 | | * include one of these chunks in their first frame. |
772 | | * Why I do not know, it seems rather extraneous. */ |
773 | 727 | ff_dlog(avctx, |
774 | 727 | "Unexpected Palette chunk %d in non-palettized FLC\n", |
775 | 727 | chunk_type); |
776 | 727 | bytestream2_skip(&g2, chunk_size - 6); |
777 | 727 | break; |
778 | | |
779 | 2.05k | case FLI_DELTA: |
780 | 2.53k | case FLI_DTA_LC: |
781 | 2.53k | y_ptr = 0; |
782 | 2.53k | compressed_lines = bytestream2_get_le16(&g2); |
783 | 7.80k | while (compressed_lines > 0) { |
784 | 7.28k | if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk) |
785 | 908 | break; |
786 | 6.37k | CHECK_Y_PTR() |
787 | 6.12k | line_packets = sign_extend(bytestream2_get_le16(&g2), 16); |
788 | 6.12k | if (line_packets < 0) { |
789 | 1.22k | line_packets = -line_packets; |
790 | 1.22k | if (line_packets > s->avctx->height) |
791 | 415 | return AVERROR_INVALIDDATA; |
792 | 808 | y_ptr += line_packets * s->frame->linesize[0]; |
793 | 4.89k | } else { |
794 | 4.89k | compressed_lines--; |
795 | 4.89k | pixel_ptr = y_ptr; |
796 | 4.89k | CHECK_PIXEL_PTR(0); |
797 | 4.89k | pixel_countdown = s->avctx->width; |
798 | 613k | for (i = 0; i < line_packets; i++) { |
799 | | /* account for the skip bytes */ |
800 | 611k | if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk) |
801 | 837 | break; |
802 | 610k | pixel_skip = bytestream2_get_byte(&g2); |
803 | 610k | pixel_ptr += (pixel_skip*2); /* Pixel is 2 bytes wide */ |
804 | 610k | pixel_countdown -= pixel_skip; |
805 | 610k | byte_run = sign_extend(bytestream2_get_byte(&g2), 8); |
806 | 610k | if (byte_run < 0) { |
807 | 139k | byte_run = -byte_run; |
808 | 139k | pixel = bytestream2_get_le16(&g2); |
809 | 139k | CHECK_PIXEL_PTR(2 * byte_run); |
810 | 6.08M | for (j = 0; j < byte_run; j++, pixel_countdown -= 2) { |
811 | 5.95M | *((signed short*)(&pixels[pixel_ptr])) = pixel; |
812 | 5.95M | pixel_ptr += 2; |
813 | 5.95M | } |
814 | 471k | } else { |
815 | 471k | if (bytestream2_tell(&g2) + 2*byte_run > stream_ptr_after_chunk) |
816 | 1.60k | break; |
817 | 470k | CHECK_PIXEL_PTR(2 * byte_run); |
818 | 2.75M | for (j = 0; j < byte_run; j++, pixel_countdown--) { |
819 | 2.28M | *((signed short*)(&pixels[pixel_ptr])) = bytestream2_get_le16(&g2); |
820 | 2.28M | pixel_ptr += 2; |
821 | 2.28M | } |
822 | 469k | } |
823 | 610k | } |
824 | | |
825 | 4.46k | y_ptr += s->frame->linesize[0]; |
826 | 4.46k | } |
827 | 6.12k | } |
828 | 1.43k | break; |
829 | | |
830 | 1.43k | case FLI_LC: |
831 | 478 | av_log(avctx, AV_LOG_ERROR, "Unexpected FLI_LC chunk in non-palettized FLC\n"); |
832 | 478 | bytestream2_skip(&g2, chunk_size - 6); |
833 | 478 | break; |
834 | | |
835 | 238 | case FLI_BLACK: |
836 | | /* set the whole frame to 0x0000 which is black in both 15Bpp and 16Bpp modes. */ |
837 | 2.24M | for (int y = 0; y < s->avctx->height; y++) |
838 | 2.24M | memset(pixels + y * s->frame->linesize[0], 0, s->avctx->width * 2); |
839 | 238 | break; |
840 | | |
841 | 784 | case FLI_BRUN: |
842 | 784 | y_ptr = 0; |
843 | 1.78M | for (lines = 0; lines < s->avctx->height; lines++) { |
844 | 1.78M | pixel_ptr = y_ptr; |
845 | | /* disregard the line packets; instead, iterate through all |
846 | | * pixels on a row */ |
847 | 1.78M | bytestream2_skip(&g2, 1); |
848 | 1.78M | pixel_countdown = (s->avctx->width * 2); |
849 | | |
850 | 2.40M | while (pixel_countdown > 0) { |
851 | 2.39M | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
852 | 1.76M | break; |
853 | 628k | byte_run = sign_extend(bytestream2_get_byte(&g2), 8); |
854 | 628k | if (byte_run > 0) { |
855 | 214k | palette_idx1 = bytestream2_get_byte(&g2); |
856 | 214k | CHECK_PIXEL_PTR(byte_run); |
857 | 6.70M | for (j = 0; j < byte_run; j++) { |
858 | 6.48M | pixels[pixel_ptr++] = palette_idx1; |
859 | 6.48M | pixel_countdown--; |
860 | 6.48M | if (pixel_countdown < 0) |
861 | 359k | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) (linea%d)\n", |
862 | 359k | pixel_countdown, lines); |
863 | 6.48M | } |
864 | 414k | } else { /* copy bytes if byte_run < 0 */ |
865 | 414k | byte_run = -byte_run; |
866 | 414k | if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk) |
867 | 1.17k | break; |
868 | 413k | CHECK_PIXEL_PTR(byte_run); |
869 | 3.11M | for (j = 0; j < byte_run; j++) { |
870 | 2.70M | palette_idx1 = bytestream2_get_byte(&g2); |
871 | 2.70M | pixels[pixel_ptr++] = palette_idx1; |
872 | 2.70M | pixel_countdown--; |
873 | 2.70M | if (pixel_countdown < 0) |
874 | 286k | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n", |
875 | 286k | pixel_countdown, lines); |
876 | 2.70M | } |
877 | 413k | } |
878 | 628k | } |
879 | | |
880 | | /* Now FLX is strange, in that it is "byte" as opposed to "pixel" run length compressed. |
881 | | * This does not give us any good opportunity to perform word endian conversion |
882 | | * during decompression. So if it is required (i.e., this is not a LE target, we do |
883 | | * a second pass over the line here, swapping the bytes. |
884 | | */ |
885 | | #if HAVE_BIGENDIAN |
886 | | pixel_ptr = y_ptr; |
887 | | pixel_countdown = s->avctx->width; |
888 | | while (pixel_countdown > 0) { |
889 | | *((signed short*)(&pixels[pixel_ptr])) = AV_RL16(&buf[pixel_ptr]); |
890 | | pixel_ptr += 2; |
891 | | } |
892 | | #endif |
893 | 1.78M | y_ptr += s->frame->linesize[0]; |
894 | 1.78M | } |
895 | 377 | break; |
896 | | |
897 | 850 | case FLI_DTA_BRUN: |
898 | 850 | y_ptr = 0; |
899 | 1.61M | for (lines = 0; lines < s->avctx->height; lines++) { |
900 | 1.61M | pixel_ptr = y_ptr; |
901 | | /* disregard the line packets; instead, iterate through all |
902 | | * pixels on a row */ |
903 | 1.61M | bytestream2_skip(&g2, 1); |
904 | 1.61M | pixel_countdown = s->avctx->width; /* Width is in pixels, not bytes */ |
905 | | |
906 | 1.97M | while (pixel_countdown > 0) { |
907 | 1.96M | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
908 | 1.59M | break; |
909 | 365k | byte_run = sign_extend(bytestream2_get_byte(&g2), 8); |
910 | 365k | if (byte_run > 0) { |
911 | 111k | pixel = bytestream2_get_le16(&g2); |
912 | 111k | CHECK_PIXEL_PTR(2 * byte_run); |
913 | 2.29M | for (j = 0; j < byte_run; j++) { |
914 | 2.18M | *((signed short*)(&pixels[pixel_ptr])) = pixel; |
915 | 2.18M | pixel_ptr += 2; |
916 | 2.18M | pixel_countdown--; |
917 | 2.18M | if (pixel_countdown < 0) |
918 | 293k | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n", |
919 | 293k | pixel_countdown); |
920 | 2.18M | } |
921 | 254k | } else { /* copy pixels if byte_run < 0 */ |
922 | 254k | byte_run = -byte_run; |
923 | 254k | if (bytestream2_tell(&g2) + 2 * byte_run > stream_ptr_after_chunk) |
924 | 988 | break; |
925 | 253k | CHECK_PIXEL_PTR(2 * byte_run); |
926 | 2.12M | for (j = 0; j < byte_run; j++) { |
927 | 1.87M | *((signed short*)(&pixels[pixel_ptr])) = bytestream2_get_le16(&g2); |
928 | 1.87M | pixel_ptr += 2; |
929 | 1.87M | pixel_countdown--; |
930 | 1.87M | if (pixel_countdown < 0) |
931 | 310k | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n", |
932 | 310k | pixel_countdown); |
933 | 1.87M | } |
934 | 252k | } |
935 | 365k | } |
936 | | |
937 | 1.61M | y_ptr += s->frame->linesize[0]; |
938 | 1.61M | } |
939 | 454 | break; |
940 | | |
941 | 993 | case FLI_COPY: |
942 | 1.22k | case FLI_DTA_COPY: |
943 | | /* copy the chunk (uncompressed frame) */ |
944 | 1.22k | if (chunk_size - 6 > (unsigned int)(FFALIGN(s->avctx->width, 2) * s->avctx->height)*2) { |
945 | 679 | av_log(avctx, AV_LOG_ERROR, "In chunk FLI_COPY : source data (%d bytes) " \ |
946 | 679 | "bigger than image, skipping chunk\n", chunk_size - 6); |
947 | 679 | bytestream2_skip(&g2, chunk_size - 6); |
948 | 679 | } else { |
949 | | |
950 | 547 | if (bytestream2_get_bytes_left(&g2) < 2 * s->avctx->width * s->avctx->height ) |
951 | 299 | return AVERROR_INVALIDDATA; |
952 | 17.4k | for (y_ptr = 0; check_pixel_ptr(y_ptr, 2*s->avctx->width, pixel_limit, direction) == 0; |
953 | 17.2k | y_ptr += s->frame->linesize[0]) { |
954 | | |
955 | 17.2k | pixel_countdown = s->avctx->width; |
956 | 17.2k | pixel_ptr = 0; |
957 | 91.8k | while (pixel_countdown > 0) { |
958 | 74.5k | *((signed short*)(&pixels[y_ptr + pixel_ptr])) = bytestream2_get_le16(&g2); |
959 | 74.5k | pixel_ptr += 2; |
960 | 74.5k | pixel_countdown--; |
961 | 74.5k | } |
962 | 17.2k | if (s->avctx->width & 1) |
963 | 16.8k | bytestream2_skip(&g2, 2); |
964 | 17.2k | } |
965 | 248 | } |
966 | 927 | break; |
967 | | |
968 | 927 | case FLI_MINI: |
969 | | /* some sort of a thumbnail? disregard this chunk... */ |
970 | 433 | bytestream2_skip(&g2, chunk_size - 6); |
971 | 433 | break; |
972 | | |
973 | 2.29k | default: |
974 | 2.29k | av_log(avctx, AV_LOG_ERROR, "Unrecognized chunk type: %d\n", chunk_type); |
975 | 2.29k | break; |
976 | 9.56k | } |
977 | | |
978 | 7.35k | if (stream_ptr_after_chunk - bytestream2_tell(&g2) >= 0) { |
979 | 6.25k | bytestream2_skip(&g2, stream_ptr_after_chunk - bytestream2_tell(&g2)); |
980 | 6.25k | } else { |
981 | 1.10k | av_log(avctx, AV_LOG_ERROR, "Chunk overread\n"); |
982 | 1.10k | break; |
983 | 1.10k | } |
984 | | |
985 | 6.25k | frame_size -= chunk_size; |
986 | 6.25k | num_chunks--; |
987 | 6.25k | } |
988 | | |
989 | | /* by the end of the chunk, the stream ptr should equal the frame |
990 | | * size (minus 1, possibly); if it doesn't, issue a warning */ |
991 | 8.53k | if ((bytestream2_get_bytes_left(&g2) != 0) && (bytestream2_get_bytes_left(&g2) != 1)) |
992 | 1.34k | av_log(avctx, AV_LOG_ERROR, "Processed FLI chunk where chunk size = %d " \ |
993 | 1.34k | "and final chunk ptr = %d\n", buf_size, bytestream2_tell(&g2)); |
994 | | |
995 | 8.53k | if ((ret = av_frame_ref(rframe, s->frame)) < 0) |
996 | 0 | return ret; |
997 | | |
998 | 8.53k | *got_frame = 1; |
999 | | |
1000 | 8.53k | return buf_size; |
1001 | 8.53k | } |
1002 | | |
1003 | | static int flic_decode_frame_24BPP(AVCodecContext *avctx, |
1004 | | AVFrame *rframe, int *got_frame, |
1005 | | const uint8_t *buf, int buf_size) |
1006 | 11.6k | { |
1007 | 11.6k | FlicDecodeContext *s = avctx->priv_data; |
1008 | | |
1009 | 11.6k | GetByteContext g2; |
1010 | 11.6k | ptrdiff_t pixel_ptr; |
1011 | 11.6k | unsigned char palette_idx1; |
1012 | | |
1013 | 11.6k | unsigned int frame_size; |
1014 | 11.6k | int num_chunks; |
1015 | | |
1016 | 11.6k | unsigned int chunk_size; |
1017 | 11.6k | int chunk_type; |
1018 | | |
1019 | 11.6k | int i, j, ret, direction; |
1020 | | |
1021 | 11.6k | int lines; |
1022 | 11.6k | int compressed_lines; |
1023 | 11.6k | int line_packets; |
1024 | 11.6k | ptrdiff_t y_ptr; |
1025 | 11.6k | int byte_run; |
1026 | 11.6k | int pixel_skip; |
1027 | 11.6k | int pixel_countdown; |
1028 | 11.6k | unsigned char *pixels; |
1029 | 11.6k | int pixel; |
1030 | 11.6k | ptrdiff_t pixel_limit; |
1031 | | |
1032 | 11.6k | bytestream2_init(&g2, buf, buf_size); |
1033 | | |
1034 | 11.6k | if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0) |
1035 | 211 | return ret; |
1036 | | |
1037 | 11.4k | direction = s->frame->linesize[0] > 0; |
1038 | 11.4k | pixels = s->frame->data[0]; |
1039 | 11.4k | pixel_limit = s->avctx->height * s->frame->linesize[0]; |
1040 | | |
1041 | 11.4k | frame_size = bytestream2_get_le32(&g2); |
1042 | 11.4k | bytestream2_skip(&g2, 2); /* skip the magic number */ |
1043 | 11.4k | num_chunks = bytestream2_get_le16(&g2); |
1044 | 11.4k | bytestream2_skip(&g2, 8); /* skip padding */ |
1045 | 11.4k | if (frame_size > buf_size) |
1046 | 10.1k | frame_size = buf_size; |
1047 | | |
1048 | 11.4k | if (frame_size < 16) |
1049 | 1.77k | return AVERROR_INVALIDDATA; |
1050 | 9.70k | frame_size -= 16; |
1051 | | |
1052 | | /* iterate through the chunks */ |
1053 | 15.8k | while ((frame_size > 0) && (num_chunks > 0) && |
1054 | 15.8k | bytestream2_get_bytes_left(&g2) >= 4) { |
1055 | 9.38k | int stream_ptr_after_chunk; |
1056 | 9.38k | chunk_size = bytestream2_get_le32(&g2); |
1057 | 9.38k | if (chunk_size > frame_size) { |
1058 | 6.91k | av_log(avctx, AV_LOG_WARNING, |
1059 | 6.91k | "Invalid chunk_size = %u > frame_size = %u\n", chunk_size, frame_size); |
1060 | 6.91k | chunk_size = frame_size; |
1061 | 6.91k | } |
1062 | 9.38k | stream_ptr_after_chunk = bytestream2_tell(&g2) - 4 + chunk_size; |
1063 | | |
1064 | 9.38k | chunk_type = bytestream2_get_le16(&g2); |
1065 | | |
1066 | | |
1067 | 9.38k | switch (chunk_type) { |
1068 | 481 | case FLI_256_COLOR: |
1069 | 714 | case FLI_COLOR: |
1070 | | /* For some reason, it seems that non-palettized flics do |
1071 | | * include one of these chunks in their first frame. |
1072 | | * Why I do not know, it seems rather extraneous. */ |
1073 | 714 | ff_dlog(avctx, |
1074 | 714 | "Unexpected Palette chunk %d in non-palettized FLC\n", |
1075 | 714 | chunk_type); |
1076 | 714 | bytestream2_skip(&g2, chunk_size - 6); |
1077 | 714 | break; |
1078 | | |
1079 | 2.15k | case FLI_DELTA: |
1080 | 2.38k | case FLI_DTA_LC: |
1081 | 2.38k | y_ptr = 0; |
1082 | 2.38k | compressed_lines = bytestream2_get_le16(&g2); |
1083 | 7.28k | while (compressed_lines > 0) { |
1084 | 6.71k | if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk) |
1085 | 868 | break; |
1086 | 5.84k | CHECK_Y_PTR() |
1087 | 5.62k | line_packets = sign_extend(bytestream2_get_le16(&g2), 16); |
1088 | 5.62k | if (line_packets < 0) { |
1089 | 1.10k | line_packets = -line_packets; |
1090 | 1.10k | if (line_packets > s->avctx->height) |
1091 | 285 | return AVERROR_INVALIDDATA; |
1092 | 816 | y_ptr += line_packets * s->frame->linesize[0]; |
1093 | 4.52k | } else { |
1094 | 4.52k | compressed_lines--; |
1095 | 4.52k | pixel_ptr = y_ptr; |
1096 | 4.52k | CHECK_PIXEL_PTR(0); |
1097 | 4.52k | pixel_countdown = s->avctx->width; |
1098 | 662k | for (i = 0; i < line_packets; i++) { |
1099 | | /* account for the skip bytes */ |
1100 | 660k | if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk) |
1101 | 791 | break; |
1102 | 659k | pixel_skip = bytestream2_get_byte(&g2); |
1103 | 659k | pixel_ptr += (pixel_skip*3); /* Pixel is 3 bytes wide */ |
1104 | 659k | pixel_countdown -= pixel_skip; |
1105 | 659k | byte_run = sign_extend(bytestream2_get_byte(&g2), 8); |
1106 | 659k | if (byte_run < 0) { |
1107 | 167k | byte_run = -byte_run; |
1108 | 167k | pixel = bytestream2_get_le24(&g2); |
1109 | 167k | CHECK_PIXEL_PTR(3 * byte_run); |
1110 | 6.38M | for (j = 0; j < byte_run; j++, pixel_countdown -= 1) { |
1111 | 6.22M | AV_WL24(&pixels[pixel_ptr], pixel); |
1112 | 6.22M | pixel_ptr += 3; |
1113 | 6.22M | } |
1114 | 492k | } else { |
1115 | 492k | if (bytestream2_tell(&g2) + 2*byte_run > stream_ptr_after_chunk) |
1116 | 1.59k | break; |
1117 | 491k | CHECK_PIXEL_PTR(3 * byte_run); |
1118 | 2.75M | for (j = 0; j < byte_run; j++, pixel_countdown--) { |
1119 | 2.26M | pixel = bytestream2_get_le24(&g2); |
1120 | 2.26M | AV_WL24(&pixels[pixel_ptr], pixel); |
1121 | 2.26M | pixel_ptr += 3; |
1122 | 2.26M | } |
1123 | 490k | } |
1124 | 659k | } |
1125 | | |
1126 | 4.08k | y_ptr += s->frame->linesize[0]; |
1127 | 4.08k | } |
1128 | 5.62k | } |
1129 | 1.43k | break; |
1130 | | |
1131 | 1.43k | case FLI_LC: |
1132 | 741 | av_log(avctx, AV_LOG_ERROR, "Unexpected FLI_LC chunk in non-palettized FLC\n"); |
1133 | 741 | bytestream2_skip(&g2, chunk_size - 6); |
1134 | 741 | break; |
1135 | | |
1136 | 266 | case FLI_BLACK: |
1137 | | /* set the whole frame to 0x00 which is black for 24 bit mode. */ |
1138 | 2.28M | for (int y = 0; y < s->avctx->height; y++) |
1139 | 2.28M | memset(pixels + y * s->frame->linesize[0], 0, s->avctx->width * 3); |
1140 | 266 | break; |
1141 | | |
1142 | 925 | case FLI_BRUN: |
1143 | 925 | y_ptr = 0; |
1144 | 2.23M | for (lines = 0; lines < s->avctx->height; lines++) { |
1145 | 2.23M | pixel_ptr = y_ptr; |
1146 | | /* disregard the line packets; instead, iterate through all |
1147 | | * pixels on a row */ |
1148 | 2.23M | bytestream2_skip(&g2, 1); |
1149 | 2.23M | pixel_countdown = (s->avctx->width * 3); |
1150 | | |
1151 | 3.12M | while (pixel_countdown > 0) { |
1152 | 3.12M | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
1153 | 2.23M | break; |
1154 | 893k | byte_run = sign_extend(bytestream2_get_byte(&g2), 8); |
1155 | 893k | if (byte_run > 0) { |
1156 | 359k | palette_idx1 = bytestream2_get_byte(&g2); |
1157 | 359k | CHECK_PIXEL_PTR(byte_run); |
1158 | 10.2M | for (j = 0; j < byte_run; j++) { |
1159 | 9.91M | pixels[pixel_ptr++] = palette_idx1; |
1160 | 9.91M | pixel_countdown--; |
1161 | 9.91M | if (pixel_countdown < 0) |
1162 | 50.4k | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) (linea%d)\n", |
1163 | 50.4k | pixel_countdown, lines); |
1164 | 9.91M | } |
1165 | 533k | } else { /* copy bytes if byte_run < 0 */ |
1166 | 533k | byte_run = -byte_run; |
1167 | 533k | if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk) |
1168 | 906 | break; |
1169 | 533k | CHECK_PIXEL_PTR(byte_run); |
1170 | 5.23M | for (j = 0; j < byte_run; j++) { |
1171 | 4.70M | palette_idx1 = bytestream2_get_byte(&g2); |
1172 | 4.70M | pixels[pixel_ptr++] = palette_idx1; |
1173 | 4.70M | pixel_countdown--; |
1174 | 4.70M | if (pixel_countdown < 0) |
1175 | 16.5k | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n", |
1176 | 16.5k | pixel_countdown, lines); |
1177 | 4.70M | } |
1178 | 532k | } |
1179 | 893k | } |
1180 | | |
1181 | 2.23M | y_ptr += s->frame->linesize[0]; |
1182 | 2.23M | } |
1183 | 516 | break; |
1184 | | |
1185 | 993 | case FLI_DTA_BRUN: |
1186 | 993 | y_ptr = 0; |
1187 | 3.08M | for (lines = 0; lines < s->avctx->height; lines++) { |
1188 | 3.08M | pixel_ptr = y_ptr; |
1189 | | /* disregard the line packets; instead, iterate through all |
1190 | | * pixels on a row */ |
1191 | 3.08M | bytestream2_skip(&g2, 1); |
1192 | 3.08M | pixel_countdown = s->avctx->width; /* Width is in pixels, not bytes */ |
1193 | | |
1194 | 3.30M | while (pixel_countdown > 0) { |
1195 | 3.30M | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
1196 | 3.08M | break; |
1197 | 219k | byte_run = sign_extend(bytestream2_get_byte(&g2), 8); |
1198 | 219k | if (byte_run > 0) { |
1199 | 36.8k | pixel = bytestream2_get_le24(&g2); |
1200 | 36.8k | CHECK_PIXEL_PTR(3 * byte_run); |
1201 | 1.48M | for (j = 0; j < byte_run; j++) { |
1202 | 1.44M | AV_WL24(pixels + pixel_ptr, pixel); |
1203 | 1.44M | pixel_ptr += 3; |
1204 | 1.44M | pixel_countdown--; |
1205 | 1.44M | if (pixel_countdown < 0) |
1206 | 33.9k | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n", |
1207 | 33.9k | pixel_countdown); |
1208 | 1.44M | } |
1209 | 182k | } else { /* copy pixels if byte_run < 0 */ |
1210 | 182k | byte_run = -byte_run; |
1211 | 182k | if (bytestream2_tell(&g2) + 3 * byte_run > stream_ptr_after_chunk) |
1212 | 1.29k | break; |
1213 | 181k | CHECK_PIXEL_PTR(3 * byte_run); |
1214 | 1.48M | for (j = 0; j < byte_run; j++) { |
1215 | 1.30M | pixel = bytestream2_get_le24(&g2); |
1216 | 1.30M | AV_WL24(pixels + pixel_ptr, pixel); |
1217 | 1.30M | pixel_ptr += 3; |
1218 | 1.30M | pixel_countdown--; |
1219 | 1.30M | if (pixel_countdown < 0) |
1220 | 14.0k | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n", |
1221 | 14.0k | pixel_countdown); |
1222 | 1.30M | } |
1223 | 181k | } |
1224 | 219k | } |
1225 | | |
1226 | 3.08M | y_ptr += s->frame->linesize[0]; |
1227 | 3.08M | } |
1228 | 517 | break; |
1229 | | |
1230 | 624 | case FLI_COPY: |
1231 | 862 | case FLI_DTA_COPY: |
1232 | | /* copy the chunk (uncompressed frame) */ |
1233 | 862 | if (chunk_size - 6 > (unsigned int)(FFALIGN(s->avctx->width, 2) * s->avctx->height)*3) { |
1234 | 478 | av_log(avctx, AV_LOG_ERROR, "In chunk FLI_COPY : source data (%d bytes) " \ |
1235 | 478 | "bigger than image, skipping chunk\n", chunk_size - 6); |
1236 | 478 | bytestream2_skip(&g2, chunk_size - 6); |
1237 | 478 | } else { |
1238 | 1.61M | for (y_ptr = 0; check_pixel_ptr(y_ptr, 3*s->avctx->width, pixel_limit, direction) == 0; |
1239 | 1.61M | y_ptr += s->frame->linesize[0]) { |
1240 | | |
1241 | 1.61M | bytestream2_get_buffer(&g2, pixels + y_ptr, 3*s->avctx->width); |
1242 | 1.61M | if (s->avctx->width & 1) |
1243 | 304k | bytestream2_skip(&g2, 3); |
1244 | 1.61M | } |
1245 | 384 | } |
1246 | 862 | break; |
1247 | | |
1248 | 672 | case FLI_MINI: |
1249 | | /* some sort of a thumbnail? disregard this chunk... */ |
1250 | 672 | bytestream2_skip(&g2, chunk_size - 6); |
1251 | 672 | break; |
1252 | | |
1253 | 1.83k | default: |
1254 | 1.83k | av_log(avctx, AV_LOG_ERROR, "Unrecognized chunk type: %d\n", chunk_type); |
1255 | 1.83k | break; |
1256 | 9.38k | } |
1257 | | |
1258 | 7.56k | if (stream_ptr_after_chunk - bytestream2_tell(&g2) >= 0) { |
1259 | 6.14k | bytestream2_skip(&g2, stream_ptr_after_chunk - bytestream2_tell(&g2)); |
1260 | 6.14k | } else { |
1261 | 1.41k | av_log(avctx, AV_LOG_ERROR, "Chunk overread\n"); |
1262 | 1.41k | break; |
1263 | 1.41k | } |
1264 | | |
1265 | 6.14k | frame_size -= chunk_size; |
1266 | 6.14k | num_chunks--; |
1267 | 6.14k | } |
1268 | | |
1269 | | /* by the end of the chunk, the stream ptr should equal the frame |
1270 | | * size (minus 1, possibly); if it doesn't, issue a warning */ |
1271 | 7.87k | if ((bytestream2_get_bytes_left(&g2) != 0) && (bytestream2_get_bytes_left(&g2) != 1)) |
1272 | 1.00k | av_log(avctx, AV_LOG_ERROR, "Processed FLI chunk where chunk size = %d " \ |
1273 | 1.00k | "and final chunk ptr = %d\n", buf_size, bytestream2_tell(&g2)); |
1274 | | |
1275 | 7.87k | if ((ret = av_frame_ref(rframe, s->frame)) < 0) |
1276 | 0 | return ret; |
1277 | | |
1278 | 7.87k | *got_frame = 1; |
1279 | | |
1280 | 7.87k | return buf_size; |
1281 | 7.87k | } |
1282 | | |
1283 | | static int flic_decode_frame(AVCodecContext *avctx, AVFrame *frame, |
1284 | | int *got_frame, AVPacket *avpkt) |
1285 | 146k | { |
1286 | 146k | const uint8_t *buf = avpkt->data; |
1287 | 146k | int buf_size = avpkt->size; |
1288 | 146k | if (avctx->pix_fmt == AV_PIX_FMT_MONOBLACK) { |
1289 | 9.03k | return flic_decode_frame_1BPP(avctx, frame, got_frame, |
1290 | 9.03k | buf, buf_size); |
1291 | 137k | } else if (avctx->pix_fmt == AV_PIX_FMT_PAL8) { |
1292 | 113k | return flic_decode_frame_8BPP(avctx, frame, got_frame, |
1293 | 113k | buf, buf_size); |
1294 | 113k | } else if ((avctx->pix_fmt == AV_PIX_FMT_RGB555) || |
1295 | 23.9k | (avctx->pix_fmt == AV_PIX_FMT_RGB565)) { |
1296 | 12.2k | return flic_decode_frame_15_16BPP(avctx, frame, got_frame, |
1297 | 12.2k | buf, buf_size); |
1298 | 12.2k | } else if (avctx->pix_fmt == AV_PIX_FMT_BGR24) { |
1299 | 11.6k | return flic_decode_frame_24BPP(avctx, frame, got_frame, |
1300 | 11.6k | buf, buf_size); |
1301 | 11.6k | } |
1302 | | |
1303 | | /* Should not get here, ever as the pix_fmt is processed */ |
1304 | | /* in flic_decode_init and the above if should deal with */ |
1305 | | /* the finite set of possibilities allowable by here. */ |
1306 | | /* But in case we do, just error out. */ |
1307 | 0 | av_log(avctx, AV_LOG_ERROR, "Unknown FLC format, my science cannot explain how this happened.\n"); |
1308 | 0 | return AVERROR_BUG; |
1309 | 146k | } |
1310 | | |
1311 | | |
1312 | | static av_cold int flic_decode_end(AVCodecContext *avctx) |
1313 | 2.63k | { |
1314 | 2.63k | FlicDecodeContext *s = avctx->priv_data; |
1315 | | |
1316 | 2.63k | av_frame_free(&s->frame); |
1317 | | |
1318 | 2.63k | return 0; |
1319 | 2.63k | } |
1320 | | |
1321 | | const FFCodec ff_flic_decoder = { |
1322 | | .p.name = "flic", |
1323 | | CODEC_LONG_NAME("Autodesk Animator Flic video"), |
1324 | | .p.type = AVMEDIA_TYPE_VIDEO, |
1325 | | .p.id = AV_CODEC_ID_FLIC, |
1326 | | .priv_data_size = sizeof(FlicDecodeContext), |
1327 | | .init = flic_decode_init, |
1328 | | .close = flic_decode_end, |
1329 | | FF_CODEC_DECODE_CB(flic_decode_frame), |
1330 | | .p.capabilities = AV_CODEC_CAP_DR1, |
1331 | | }; |