/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.31k | #define FLI_256_COLOR 4 |
47 | 7.33k | #define FLI_DELTA 7 |
48 | 3.47k | #define FLI_COLOR 11 |
49 | 5.16k | #define FLI_LC 12 |
50 | 733 | #define FLI_BLACK 13 |
51 | 4.20k | #define FLI_BRUN 15 |
52 | 3.33k | #define FLI_COPY 16 |
53 | 1.14k | #define FLI_MINI 18 |
54 | 1.86k | #define FLI_DTA_BRUN 25 |
55 | 2.41k | #define FLI_DTA_COPY 26 |
56 | 5.23k | #define FLI_DTA_LC 27 |
57 | | |
58 | 1.07k | #define FLI_TYPE_CODE (0xAF11) |
59 | 2.71k | #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.27k | #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.48M | { |
66 | 8.48M | if (( direction && ptr + n > limit) || |
67 | 8.48M | (!direction && ptr + n < limit)) |
68 | 7.81k | return AVERROR_INVALIDDATA; |
69 | 8.47M | return 0; |
70 | 8.48M | } |
71 | | |
72 | 6.79M | #define CHECK_PIXEL_PTR(n) \ |
73 | 6.79M | { \ |
74 | 6.79M | ret = check_pixel_ptr(pixel_ptr, (n), pixel_limit, direction); \ |
75 | 6.79M | if (ret < 0) \ |
76 | 6.79M | return ret; \ |
77 | 6.79M | } |
78 | | |
79 | 25.7k | #define CHECK_Y_PTR() \ |
80 | 25.7k | { \ |
81 | 25.7k | ret = check_pixel_ptr(y_ptr, 0, pixel_limit, direction); \ |
82 | 25.7k | if (ret < 0) \ |
83 | 25.7k | return ret; \ |
84 | 25.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.77k | { |
97 | 2.77k | FlicDecodeContext *s = avctx->priv_data; |
98 | 2.77k | uint8_t *fli_header = avctx->extradata; |
99 | 2.77k | int depth; |
100 | | |
101 | 2.77k | if (avctx->extradata_size != 0 && |
102 | 2.77k | avctx->extradata_size != 12 && |
103 | 2.77k | avctx->extradata_size != 128 && |
104 | 2.77k | avctx->extradata_size != 256 && |
105 | 2.77k | avctx->extradata_size != 904 && |
106 | 2.77k | avctx->extradata_size != 1024) { |
107 | 58 | av_log(avctx, AV_LOG_ERROR, "Unexpected extradata size %d\n", avctx->extradata_size); |
108 | 58 | return AVERROR_INVALIDDATA; |
109 | 58 | } |
110 | | |
111 | 2.71k | s->avctx = avctx; |
112 | | |
113 | 2.71k | if (s->avctx->extradata_size == 12) { |
114 | | /* special case for magic carpet FLIs */ |
115 | 9 | s->fli_type = FLC_MAGIC_CARPET_SYNTHETIC_TYPE_CODE; |
116 | 9 | depth = 8; |
117 | 2.71k | } else if (avctx->extradata_size == 1024) { |
118 | 3 | uint8_t *ptr = avctx->extradata; |
119 | 3 | int i; |
120 | | |
121 | 771 | for (i = 0; i < 256; i++) { |
122 | 768 | s->palette[i] = AV_RL32(ptr); |
123 | 768 | ptr += 4; |
124 | 768 | } |
125 | 3 | depth = 8; |
126 | | /* FLI in MOV, see e.g. FFmpeg trac issue #626 */ |
127 | 2.70k | } else if (avctx->extradata_size == 0 || |
128 | 2.70k | avctx->extradata_size == 256 || |
129 | | /* see FFmpeg ticket #1234 */ |
130 | 2.70k | avctx->extradata_size == 904) { |
131 | 1.07k | s->fli_type = FLI_TYPE_CODE; |
132 | 1.07k | depth = 8; |
133 | 1.63k | } else { |
134 | 1.63k | s->fli_type = AV_RL16(&fli_header[4]); |
135 | 1.63k | depth = AV_RL16(&fli_header[12]); |
136 | 1.63k | } |
137 | | |
138 | 2.71k | if (depth == 0) { |
139 | 97 | depth = 8; /* Some FLC generators set depth to zero, when they mean 8Bpp. Fix up here */ |
140 | 97 | } |
141 | | |
142 | 2.71k | 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.71k | switch (depth) { |
147 | 344 | case 1 : avctx->pix_fmt = AV_PIX_FMT_MONOBLACK; break; |
148 | 1.18k | case 8 : avctx->pix_fmt = AV_PIX_FMT_PAL8; break; |
149 | 157 | case 15 : avctx->pix_fmt = AV_PIX_FMT_RGB555; break; |
150 | 440 | case 16 : avctx->pix_fmt = AV_PIX_FMT_RGB565; break; |
151 | 581 | case 24 : avctx->pix_fmt = AV_PIX_FMT_BGR24; break; |
152 | 12 | default : |
153 | 12 | av_log(avctx, AV_LOG_ERROR, "Unknown FLC/FLX depth of %d Bpp is unsupported.\n",depth); |
154 | 12 | return AVERROR_INVALIDDATA; |
155 | 2.71k | } |
156 | | |
157 | 2.70k | s->frame = av_frame_alloc(); |
158 | 2.70k | if (!s->frame) |
159 | 0 | return AVERROR(ENOMEM); |
160 | | |
161 | 2.70k | s->new_palette = 0; |
162 | | |
163 | 2.70k | return 0; |
164 | 2.70k | } |
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 | 7.40k | { |
170 | 7.40k | FlicDecodeContext *s = avctx->priv_data; |
171 | | |
172 | 7.40k | GetByteContext g2; |
173 | 7.40k | ptrdiff_t pixel_ptr; |
174 | | |
175 | 7.40k | unsigned int frame_size; |
176 | 7.40k | int num_chunks; |
177 | | |
178 | 7.40k | unsigned int chunk_size; |
179 | 7.40k | int chunk_type; |
180 | | |
181 | 7.40k | int i, j, ret, direction; |
182 | | |
183 | 7.40k | int lines; |
184 | 7.40k | int compressed_lines; |
185 | 7.40k | int starting_line; |
186 | 7.40k | int line_packets; |
187 | 7.40k | ptrdiff_t y_ptr; |
188 | 7.40k | int byte_run; |
189 | 7.40k | int pixel_skip; |
190 | 7.40k | int pixel_countdown; |
191 | 7.40k | unsigned char *pixels; |
192 | 7.40k | ptrdiff_t pixel_limit; |
193 | | |
194 | 7.40k | bytestream2_init(&g2, buf, buf_size); |
195 | | |
196 | 7.40k | if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0) |
197 | 218 | return ret; |
198 | | |
199 | 7.18k | direction = s->frame->linesize[0] > 0; |
200 | 7.18k | pixels = s->frame->data[0]; |
201 | 7.18k | pixel_limit = s->avctx->height * s->frame->linesize[0]; |
202 | 7.18k | if (buf_size < 16 || buf_size > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE) |
203 | 617 | return AVERROR_INVALIDDATA; |
204 | 6.56k | frame_size = bytestream2_get_le32(&g2); |
205 | 6.56k | if (frame_size > buf_size) |
206 | 6.30k | frame_size = buf_size; |
207 | 6.56k | bytestream2_skip(&g2, 2); /* skip the magic number */ |
208 | 6.56k | num_chunks = bytestream2_get_le16(&g2); |
209 | 6.56k | bytestream2_skip(&g2, 8); /* skip padding */ |
210 | | |
211 | 6.56k | if (frame_size < 16) |
212 | 245 | return AVERROR_INVALIDDATA; |
213 | | |
214 | 6.32k | frame_size -= 16; |
215 | | |
216 | | /* iterate through the chunks */ |
217 | 9.22k | while ((frame_size >= 6) && (num_chunks > 0) && |
218 | 9.22k | bytestream2_get_bytes_left(&g2) >= 4) { |
219 | 5.07k | int stream_ptr_after_chunk; |
220 | 5.07k | chunk_size = bytestream2_get_le32(&g2); |
221 | 5.07k | if (chunk_size > frame_size) { |
222 | 4.37k | av_log(avctx, AV_LOG_WARNING, |
223 | 4.37k | "Invalid chunk_size = %u > frame_size = %u\n", chunk_size, frame_size); |
224 | 4.37k | chunk_size = frame_size; |
225 | 4.37k | } |
226 | 5.07k | stream_ptr_after_chunk = bytestream2_tell(&g2) - 4 + chunk_size; |
227 | | |
228 | 5.07k | chunk_type = bytestream2_get_le16(&g2); |
229 | | |
230 | 5.07k | switch (chunk_type) { |
231 | 1.17k | 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.17k | y_ptr = 0; |
235 | 3.02M | for (lines = 0; lines < s->avctx->height; lines++) { |
236 | 3.02M | pixel_ptr = y_ptr; |
237 | | /* disregard the line packets; instead, iterate through all |
238 | | * pixels on a row */ |
239 | 3.02M | bytestream2_skip(&g2, 1); |
240 | 3.02M | pixel_countdown = (s->avctx->width + 7) >> 3; |
241 | 3.21M | while (pixel_countdown > 0) { |
242 | 3.05M | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
243 | 2.86M | break; |
244 | 186k | byte_run = sign_extend(bytestream2_get_byte(&g2), 8); |
245 | 186k | if (!byte_run) { |
246 | 348 | av_log(avctx, AV_LOG_ERROR, "Invalid byte run value.\n"); |
247 | 348 | return AVERROR_INVALIDDATA; |
248 | 348 | } |
249 | | |
250 | 186k | if (byte_run > 0) { |
251 | 182k | int value = bytestream2_get_byte(&g2); |
252 | 182k | CHECK_PIXEL_PTR(byte_run); |
253 | 15.0M | for (j = 0; j < byte_run; j++) { |
254 | 14.8M | pixels[pixel_ptr++] = value; |
255 | 14.8M | pixel_countdown--; |
256 | 14.8M | if (pixel_countdown < 0) |
257 | 9.75M | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n", |
258 | 9.75M | pixel_countdown, lines); |
259 | 14.8M | } |
260 | 182k | } else { /* copy bytes if byte_run < 0 */ |
261 | 4.09k | byte_run = -byte_run; |
262 | 4.09k | CHECK_PIXEL_PTR(byte_run); |
263 | 3.89k | if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk) |
264 | 940 | break; |
265 | 26.9k | for (j = 0; j < byte_run; j++) { |
266 | 23.9k | pixels[pixel_ptr++] = bytestream2_get_byte(&g2); |
267 | 23.9k | pixel_countdown--; |
268 | 23.9k | if (pixel_countdown < 0) |
269 | 12.5k | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n", |
270 | 12.5k | pixel_countdown, lines); |
271 | 23.9k | } |
272 | 2.95k | } |
273 | 186k | } |
274 | | |
275 | 3.02M | y_ptr += s->frame->linesize[0]; |
276 | 3.02M | } |
277 | 415 | 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 | 254 | 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 | 317k | while (compressed_lines > 0) { |
289 | 316k | pixel_ptr = y_ptr; |
290 | 316k | CHECK_PIXEL_PTR(0); |
291 | 316k | pixel_countdown = (s->avctx->width + 7) >> 3; |
292 | 316k | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
293 | 691 | break; |
294 | 315k | line_packets = bytestream2_get_byte(&g2); |
295 | 315k | if (line_packets > 0) { |
296 | 1.76M | for (i = 0; i < line_packets; i++) { |
297 | | /* account for the skip bytes */ |
298 | 1.71M | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
299 | 739 | break; |
300 | 1.71M | pixel_skip = bytestream2_get_byte(&g2); |
301 | 1.71M | pixel_ptr += pixel_skip; |
302 | 1.71M | pixel_countdown -= pixel_skip; |
303 | 1.71M | byte_run = sign_extend(bytestream2_get_byte(&g2),8); |
304 | 1.71M | if (byte_run > 0) { |
305 | 410k | CHECK_PIXEL_PTR(byte_run); |
306 | 410k | if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk) |
307 | 1.75k | break; |
308 | 6.96M | for (j = 0; j < byte_run; j++, pixel_countdown--) { |
309 | 6.55M | pixels[pixel_ptr++] = bytestream2_get_byte(&g2); |
310 | 6.55M | } |
311 | 1.30M | } else if (byte_run < 0) { |
312 | 479k | int value = bytestream2_get_byte(&g2); |
313 | 479k | byte_run = -byte_run; |
314 | 479k | CHECK_PIXEL_PTR(byte_run); |
315 | 22.0M | for (j = 0; j < byte_run; j++, pixel_countdown--) { |
316 | 21.5M | pixels[pixel_ptr++] = value; |
317 | 21.5M | } |
318 | 478k | } |
319 | 1.71M | } |
320 | 52.6k | } |
321 | | |
322 | 315k | y_ptr += s->frame->linesize[0]; |
323 | 315k | compressed_lines--; |
324 | 315k | } |
325 | 1.14k | break; |
326 | | |
327 | 1.65k | default: |
328 | 1.65k | av_log(avctx, AV_LOG_ERROR, "Unrecognized chunk type: %d\n", chunk_type); |
329 | 1.65k | break; |
330 | 5.07k | } |
331 | | |
332 | 3.20k | if (stream_ptr_after_chunk - bytestream2_tell(&g2) >= 0) { |
333 | 2.90k | bytestream2_skip(&g2, stream_ptr_after_chunk - bytestream2_tell(&g2)); |
334 | 2.90k | } else { |
335 | 303 | av_log(avctx, AV_LOG_ERROR, "Chunk overread\n"); |
336 | 303 | break; |
337 | 303 | } |
338 | | |
339 | 2.90k | frame_size -= chunk_size; |
340 | 2.90k | num_chunks--; |
341 | 2.90k | } |
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 | 4.45k | if (bytestream2_get_bytes_left(&g2) > 2) |
346 | 829 | av_log(avctx, AV_LOG_ERROR, "Processed FLI chunk where chunk size = %d " \ |
347 | 829 | "and final chunk ptr = %d\n", buf_size, |
348 | 829 | buf_size - bytestream2_get_bytes_left(&g2)); |
349 | | |
350 | 4.45k | if ((ret = av_frame_ref(rframe, s->frame)) < 0) |
351 | 0 | return ret; |
352 | | |
353 | 4.45k | *got_frame = 1; |
354 | | |
355 | 4.45k | return buf_size; |
356 | 4.45k | } |
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 | 185k | { |
362 | 185k | FlicDecodeContext *s = avctx->priv_data; |
363 | | |
364 | 185k | GetByteContext g2; |
365 | 185k | ptrdiff_t pixel_ptr; |
366 | 185k | int palette_ptr; |
367 | 185k | unsigned char palette_idx1; |
368 | 185k | unsigned char palette_idx2; |
369 | | |
370 | 185k | unsigned int frame_size; |
371 | 185k | int num_chunks; |
372 | | |
373 | 185k | unsigned int chunk_size; |
374 | 185k | int chunk_type; |
375 | | |
376 | 185k | int i, j, ret, direction; |
377 | | |
378 | 185k | int color_packets; |
379 | 185k | int color_changes; |
380 | 185k | int color_shift; |
381 | 185k | unsigned char r, g, b; |
382 | | |
383 | 185k | int lines; |
384 | 185k | int compressed_lines; |
385 | 185k | int starting_line; |
386 | 185k | int line_packets; |
387 | 185k | ptrdiff_t y_ptr; |
388 | 185k | int byte_run; |
389 | 185k | int pixel_skip; |
390 | 185k | int pixel_countdown; |
391 | 185k | unsigned char *pixels; |
392 | 185k | ptrdiff_t pixel_limit; |
393 | | |
394 | 185k | bytestream2_init(&g2, buf, buf_size); |
395 | | |
396 | 185k | if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0) |
397 | 71.2k | return ret; |
398 | | |
399 | 113k | direction = s->frame->linesize[0] > 0; |
400 | 113k | pixels = s->frame->data[0]; |
401 | 113k | pixel_limit = s->avctx->height * s->frame->linesize[0]; |
402 | 113k | if (buf_size < 16 || buf_size > INT_MAX - (3 * 256 + AV_INPUT_BUFFER_PADDING_SIZE)) |
403 | 6.20k | return AVERROR_INVALIDDATA; |
404 | 107k | frame_size = bytestream2_get_le32(&g2); |
405 | 107k | if (frame_size > buf_size) |
406 | 107k | frame_size = buf_size; |
407 | 107k | bytestream2_skip(&g2, 2); /* skip the magic number */ |
408 | 107k | num_chunks = bytestream2_get_le16(&g2); |
409 | 107k | bytestream2_skip(&g2, 8); /* skip padding */ |
410 | | |
411 | 107k | if (frame_size < 16) |
412 | 601 | return AVERROR_INVALIDDATA; |
413 | | |
414 | 107k | frame_size -= 16; |
415 | | |
416 | | /* iterate through the chunks */ |
417 | 124k | while ((frame_size >= 6) && (num_chunks > 0) && |
418 | 124k | bytestream2_get_bytes_left(&g2) >= 4) { |
419 | 22.1k | int stream_ptr_after_chunk; |
420 | 22.1k | chunk_size = bytestream2_get_le32(&g2); |
421 | 22.1k | if (chunk_size > frame_size) { |
422 | 19.3k | av_log(avctx, AV_LOG_WARNING, |
423 | 19.3k | "Invalid chunk_size = %u > frame_size = %u\n", chunk_size, frame_size); |
424 | 19.3k | chunk_size = frame_size; |
425 | 19.3k | } |
426 | 22.1k | stream_ptr_after_chunk = bytestream2_tell(&g2) - 4 + chunk_size; |
427 | | |
428 | 22.1k | chunk_type = bytestream2_get_le16(&g2); |
429 | | |
430 | 22.1k | switch (chunk_type) { |
431 | 1.27k | case FLI_256_COLOR: |
432 | 1.94k | 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.94k | if ((chunk_type == FLI_256_COLOR) && (s->fli_type != FLC_MAGIC_CARPET_SYNTHETIC_TYPE_CODE)) |
438 | 1.02k | color_shift = 0; |
439 | 919 | else |
440 | 919 | color_shift = 2; |
441 | | /* set up the palette */ |
442 | 1.94k | color_packets = bytestream2_get_le16(&g2); |
443 | 1.94k | palette_ptr = 0; |
444 | 113k | for (i = 0; i < color_packets; i++) { |
445 | | /* first byte is how many colors to skip */ |
446 | 112k | palette_ptr += bytestream2_get_byte(&g2); |
447 | | |
448 | | /* next byte indicates how many entries to change */ |
449 | 112k | color_changes = bytestream2_get_byte(&g2); |
450 | | |
451 | | /* if there are 0 color changes, there are actually 256 */ |
452 | 112k | if (color_changes == 0) |
453 | 4.37k | color_changes = 256; |
454 | | |
455 | 112k | if (bytestream2_tell(&g2) + color_changes * 3 > stream_ptr_after_chunk) |
456 | 978 | break; |
457 | | |
458 | 1.79M | for (j = 0; j < color_changes; j++) { |
459 | 1.68M | unsigned int entry; |
460 | | |
461 | | /* wrap around, for good measure */ |
462 | 1.68M | if ((unsigned)palette_ptr >= 256) |
463 | 8.41k | palette_ptr = 0; |
464 | | |
465 | 1.68M | r = bytestream2_get_byte(&g2) << color_shift; |
466 | 1.68M | g = bytestream2_get_byte(&g2) << color_shift; |
467 | 1.68M | b = bytestream2_get_byte(&g2) << color_shift; |
468 | 1.68M | entry = 0xFFU << 24 | r << 16 | g << 8 | b; |
469 | 1.68M | if (color_shift == 2) |
470 | 2.95k | entry |= entry >> 6 & 0x30303; |
471 | 1.68M | if (s->palette[palette_ptr] != entry) |
472 | 1.46M | s->new_palette = 1; |
473 | 1.68M | s->palette[palette_ptr++] = entry; |
474 | 1.68M | } |
475 | 111k | } |
476 | 1.94k | break; |
477 | | |
478 | 2.79k | case FLI_DELTA: |
479 | 2.79k | y_ptr = 0; |
480 | 2.79k | compressed_lines = bytestream2_get_le16(&g2); |
481 | 14.4k | while (compressed_lines > 0) { |
482 | 13.8k | if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk) |
483 | 912 | break; |
484 | 12.9k | CHECK_Y_PTR() |
485 | 12.5k | line_packets = sign_extend(bytestream2_get_le16(&g2), 16); |
486 | 12.5k | if ((line_packets & 0xC000) == 0xC000) { |
487 | | // line skip opcode |
488 | 2.80k | line_packets = -line_packets; |
489 | 2.80k | if (line_packets > s->avctx->height) |
490 | 257 | return AVERROR_INVALIDDATA; |
491 | 2.55k | y_ptr += line_packets * s->frame->linesize[0]; |
492 | 9.77k | } else if ((line_packets & 0xC000) == 0x4000) { |
493 | 1.30k | av_log(avctx, AV_LOG_ERROR, "Undefined opcode (%x) in DELTA_FLI\n", line_packets); |
494 | 8.46k | } else if ((line_packets & 0xC000) == 0x8000) { |
495 | | // "last byte" opcode |
496 | 1.10k | pixel_ptr= y_ptr + s->frame->linesize[0] - 1; |
497 | 1.10k | CHECK_PIXEL_PTR(0); |
498 | 891 | pixels[pixel_ptr] = line_packets & 0xff; |
499 | 7.36k | } else { |
500 | 7.36k | compressed_lines--; |
501 | 7.36k | pixel_ptr = y_ptr; |
502 | 7.36k | CHECK_PIXEL_PTR(0); |
503 | 7.36k | pixel_countdown = s->avctx->width; |
504 | 523k | for (i = 0; i < line_packets; i++) { |
505 | 518k | if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk) |
506 | 780 | break; |
507 | | /* account for the skip bytes */ |
508 | 518k | pixel_skip = bytestream2_get_byte(&g2); |
509 | 518k | pixel_ptr += pixel_skip; |
510 | 518k | pixel_countdown -= pixel_skip; |
511 | 518k | byte_run = sign_extend(bytestream2_get_byte(&g2), 8); |
512 | 518k | if (byte_run < 0) { |
513 | 114k | byte_run = -byte_run; |
514 | 114k | palette_idx1 = bytestream2_get_byte(&g2); |
515 | 114k | palette_idx2 = bytestream2_get_byte(&g2); |
516 | 114k | CHECK_PIXEL_PTR(byte_run * 2); |
517 | 4.17M | for (j = 0; j < byte_run; j++, pixel_countdown -= 2) { |
518 | 4.05M | pixels[pixel_ptr++] = palette_idx1; |
519 | 4.05M | pixels[pixel_ptr++] = palette_idx2; |
520 | 4.05M | } |
521 | 403k | } else { |
522 | 403k | CHECK_PIXEL_PTR(byte_run * 2); |
523 | 403k | if (bytestream2_tell(&g2) + byte_run * 2 > stream_ptr_after_chunk) |
524 | 1.05k | break; |
525 | 3.52M | for (j = 0; j < byte_run * 2; j++, pixel_countdown--) { |
526 | 3.12M | pixels[pixel_ptr++] = bytestream2_get_byte(&g2); |
527 | 3.12M | } |
528 | 402k | } |
529 | 518k | } |
530 | | |
531 | 6.92k | y_ptr += s->frame->linesize[0]; |
532 | 6.92k | } |
533 | 12.5k | } |
534 | 1.50k | break; |
535 | | |
536 | 1.98k | case FLI_LC: |
537 | | /* line compressed */ |
538 | 1.98k | starting_line = bytestream2_get_le16(&g2); |
539 | 1.98k | if (starting_line >= s->avctx->height) |
540 | 233 | return AVERROR_INVALIDDATA; |
541 | 1.74k | y_ptr = 0; |
542 | 1.74k | y_ptr += starting_line * s->frame->linesize[0]; |
543 | | |
544 | 1.74k | compressed_lines = bytestream2_get_le16(&g2); |
545 | 381k | while (compressed_lines > 0) { |
546 | 381k | pixel_ptr = y_ptr; |
547 | 381k | CHECK_PIXEL_PTR(0); |
548 | 381k | pixel_countdown = s->avctx->width; |
549 | 381k | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
550 | 624 | break; |
551 | 380k | line_packets = bytestream2_get_byte(&g2); |
552 | 380k | if (line_packets > 0) { |
553 | 1.20M | for (i = 0; i < line_packets; i++) { |
554 | | /* account for the skip bytes */ |
555 | 1.19M | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
556 | 710 | break; |
557 | 1.18M | pixel_skip = bytestream2_get_byte(&g2); |
558 | 1.18M | pixel_ptr += pixel_skip; |
559 | 1.18M | pixel_countdown -= pixel_skip; |
560 | 1.18M | byte_run = sign_extend(bytestream2_get_byte(&g2),8); |
561 | 1.18M | if (byte_run > 0) { |
562 | 263k | CHECK_PIXEL_PTR(byte_run); |
563 | 262k | if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk) |
564 | 1.48k | break; |
565 | 4.97M | for (j = 0; j < byte_run; j++, pixel_countdown--) { |
566 | 4.71M | pixels[pixel_ptr++] = bytestream2_get_byte(&g2); |
567 | 4.71M | } |
568 | 926k | } else if (byte_run < 0) { |
569 | 280k | byte_run = -byte_run; |
570 | 280k | palette_idx1 = bytestream2_get_byte(&g2); |
571 | 280k | CHECK_PIXEL_PTR(byte_run); |
572 | 14.9M | for (j = 0; j < byte_run; j++, pixel_countdown--) { |
573 | 14.6M | pixels[pixel_ptr++] = palette_idx1; |
574 | 14.6M | } |
575 | 280k | } |
576 | 1.18M | } |
577 | 18.4k | } |
578 | | |
579 | 380k | y_ptr += s->frame->linesize[0]; |
580 | 380k | compressed_lines--; |
581 | 380k | } |
582 | 1.05k | break; |
583 | | |
584 | 1.05k | case FLI_BLACK: |
585 | | /* set the whole frame to color 0 (which is usually black) */ |
586 | 1.30M | for (int y = 0; y < s->avctx->height; y++) |
587 | 1.30M | memset(pixels + y * s->frame->linesize[0], 0, s->avctx->width); |
588 | 229 | break; |
589 | | |
590 | 1.23k | 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.23k | y_ptr = 0; |
594 | 2.37M | for (lines = 0; lines < s->avctx->height; lines++) { |
595 | 2.37M | pixel_ptr = y_ptr; |
596 | | /* disregard the line packets; instead, iterate through all |
597 | | * pixels on a row */ |
598 | 2.37M | bytestream2_skip(&g2, 1); |
599 | 2.37M | pixel_countdown = s->avctx->width; |
600 | 2.73M | while (pixel_countdown > 0) { |
601 | 2.67M | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
602 | 2.31M | break; |
603 | 360k | byte_run = sign_extend(bytestream2_get_byte(&g2), 8); |
604 | 360k | if (!byte_run) { |
605 | 329 | av_log(avctx, AV_LOG_ERROR, "Invalid byte run value.\n"); |
606 | 329 | return AVERROR_INVALIDDATA; |
607 | 329 | } |
608 | | |
609 | 360k | if (byte_run > 0) { |
610 | 356k | palette_idx1 = bytestream2_get_byte(&g2); |
611 | 356k | CHECK_PIXEL_PTR(byte_run); |
612 | 9.10M | for (j = 0; j < byte_run; j++) { |
613 | 8.74M | pixels[pixel_ptr++] = palette_idx1; |
614 | 8.74M | pixel_countdown--; |
615 | 8.74M | if (pixel_countdown < 0) |
616 | 1.91M | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n", |
617 | 1.91M | pixel_countdown, lines); |
618 | 8.74M | } |
619 | 356k | } else { /* copy bytes if byte_run < 0 */ |
620 | 3.27k | byte_run = -byte_run; |
621 | 3.27k | CHECK_PIXEL_PTR(byte_run); |
622 | 3.05k | if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk) |
623 | 1.25k | break; |
624 | 18.3k | for (j = 0; j < byte_run; j++) { |
625 | 16.5k | pixels[pixel_ptr++] = bytestream2_get_byte(&g2); |
626 | 16.5k | pixel_countdown--; |
627 | 16.5k | if (pixel_countdown < 0) |
628 | 3.39k | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n", |
629 | 3.39k | pixel_countdown, lines); |
630 | 16.5k | } |
631 | 1.79k | } |
632 | 360k | } |
633 | | |
634 | 2.37M | y_ptr += s->frame->linesize[0]; |
635 | 2.37M | } |
636 | 484 | break; |
637 | | |
638 | 1.38k | case FLI_COPY: |
639 | | /* copy the chunk (uncompressed frame) */ |
640 | 1.38k | if (chunk_size - 6 != FFALIGN(s->avctx->width, 4) * s->avctx->height) { |
641 | 723 | av_log(avctx, AV_LOG_ERROR, "In chunk FLI_COPY : source data (%d bytes) " \ |
642 | 723 | "has incorrect size, skipping chunk\n", chunk_size - 6); |
643 | 723 | bytestream2_skip(&g2, chunk_size - 6); |
644 | 723 | } else { |
645 | 3.69k | for (y_ptr = 0; check_pixel_ptr(y_ptr, s->avctx->width, pixel_limit, direction) == 0; |
646 | 3.03k | y_ptr += s->frame->linesize[0]) { |
647 | 3.03k | bytestream2_get_buffer(&g2, &pixels[y_ptr], |
648 | 3.03k | s->avctx->width); |
649 | 3.03k | if (s->avctx->width & 3) |
650 | 2.06k | bytestream2_skip(&g2, 4 - (s->avctx->width & 3)); |
651 | 3.03k | } |
652 | 662 | } |
653 | 1.38k | break; |
654 | | |
655 | 248 | case FLI_MINI: |
656 | | /* some sort of a thumbnail? disregard this chunk... */ |
657 | 248 | break; |
658 | | |
659 | 12.3k | default: |
660 | 12.3k | av_log(avctx, AV_LOG_ERROR, "Unrecognized chunk type: %d\n", chunk_type); |
661 | 12.3k | break; |
662 | 22.1k | } |
663 | | |
664 | 19.2k | if (stream_ptr_after_chunk - bytestream2_tell(&g2) >= 0) { |
665 | 17.4k | bytestream2_skip(&g2, stream_ptr_after_chunk - bytestream2_tell(&g2)); |
666 | 17.4k | } else { |
667 | 1.74k | av_log(avctx, AV_LOG_ERROR, "Chunk overread\n"); |
668 | 1.74k | break; |
669 | 1.74k | } |
670 | | |
671 | 17.4k | frame_size -= chunk_size; |
672 | 17.4k | num_chunks--; |
673 | 17.4k | } |
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 | 104k | if (bytestream2_get_bytes_left(&g2) > 2) |
678 | 23.2k | av_log(avctx, AV_LOG_ERROR, "Processed FLI chunk where chunk size = %d " \ |
679 | 23.2k | "and final chunk ptr = %d\n", buf_size, |
680 | 23.2k | buf_size - bytestream2_get_bytes_left(&g2)); |
681 | | |
682 | | /* make the palette available on the way out */ |
683 | 104k | memcpy(s->frame->data[1], s->palette, AVPALETTE_SIZE); |
684 | 104k | if (s->new_palette) { |
685 | 494 | s->new_palette = 0; |
686 | 494 | } |
687 | | |
688 | 104k | if ((ret = av_frame_ref(rframe, s->frame)) < 0) |
689 | 0 | return ret; |
690 | | |
691 | 104k | *got_frame = 1; |
692 | | |
693 | 104k | return buf_size; |
694 | 104k | } |
695 | | |
696 | | static int flic_decode_frame_15_16BPP(AVCodecContext *avctx, |
697 | | AVFrame *rframe, int *got_frame, |
698 | | const uint8_t *buf, int buf_size) |
699 | 13.1k | { |
700 | | /* Note, the only difference between the 15Bpp and 16Bpp */ |
701 | | /* Format is the pixel format, the packets are processed the same. */ |
702 | 13.1k | FlicDecodeContext *s = avctx->priv_data; |
703 | | |
704 | 13.1k | GetByteContext g2; |
705 | 13.1k | ptrdiff_t pixel_ptr; |
706 | 13.1k | unsigned char palette_idx1; |
707 | | |
708 | 13.1k | unsigned int frame_size; |
709 | 13.1k | int num_chunks; |
710 | | |
711 | 13.1k | unsigned int chunk_size; |
712 | 13.1k | int chunk_type; |
713 | | |
714 | 13.1k | int i, j, ret, direction; |
715 | | |
716 | 13.1k | int lines; |
717 | 13.1k | int compressed_lines; |
718 | 13.1k | int line_packets; |
719 | 13.1k | ptrdiff_t y_ptr; |
720 | 13.1k | int byte_run; |
721 | 13.1k | int pixel_skip; |
722 | 13.1k | int pixel_countdown; |
723 | 13.1k | unsigned char *pixels; |
724 | 13.1k | int pixel; |
725 | 13.1k | ptrdiff_t pixel_limit; |
726 | | |
727 | 13.1k | bytestream2_init(&g2, buf, buf_size); |
728 | | |
729 | 13.1k | if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0) |
730 | 333 | return ret; |
731 | | |
732 | 12.8k | direction = s->frame->linesize[0] > 0; |
733 | 12.8k | pixels = s->frame->data[0]; |
734 | 12.8k | pixel_limit = s->avctx->height * s->frame->linesize[0]; |
735 | | |
736 | 12.8k | frame_size = bytestream2_get_le32(&g2); |
737 | 12.8k | bytestream2_skip(&g2, 2); /* skip the magic number */ |
738 | 12.8k | num_chunks = bytestream2_get_le16(&g2); |
739 | 12.8k | bytestream2_skip(&g2, 8); /* skip padding */ |
740 | 12.8k | if (frame_size > buf_size) |
741 | 11.6k | frame_size = buf_size; |
742 | | |
743 | 12.8k | if (frame_size < 16) |
744 | 1.05k | return AVERROR_INVALIDDATA; |
745 | 11.7k | frame_size -= 16; |
746 | | |
747 | | /* iterate through the chunks */ |
748 | 18.5k | while ((frame_size > 0) && (num_chunks > 0) && |
749 | 18.5k | bytestream2_get_bytes_left(&g2) >= 4) { |
750 | 10.3k | int stream_ptr_after_chunk; |
751 | 10.3k | chunk_size = bytestream2_get_le32(&g2); |
752 | 10.3k | if (chunk_size > frame_size) { |
753 | 7.78k | av_log(avctx, AV_LOG_WARNING, |
754 | 7.78k | "Invalid chunk_size = %u > frame_size = %u\n", chunk_size, frame_size); |
755 | 7.78k | chunk_size = frame_size; |
756 | 7.78k | } |
757 | 10.3k | stream_ptr_after_chunk = bytestream2_tell(&g2) - 4 + chunk_size; |
758 | | |
759 | 10.3k | chunk_type = bytestream2_get_le16(&g2); |
760 | | |
761 | | |
762 | 10.3k | switch (chunk_type) { |
763 | 459 | case FLI_256_COLOR: |
764 | 667 | case FLI_COLOR: |
765 | | /* For some reason, it seems that non-palettized flics do |
766 | | * include one of these chunks in their first frame. |
767 | | * Why I do not know, it seems rather extraneous. */ |
768 | 667 | ff_dlog(avctx, |
769 | 667 | "Unexpected Palette chunk %d in non-palettized FLC\n", |
770 | 667 | chunk_type); |
771 | 667 | bytestream2_skip(&g2, chunk_size - 6); |
772 | 667 | break; |
773 | | |
774 | 2.40k | case FLI_DELTA: |
775 | 2.90k | case FLI_DTA_LC: |
776 | 2.90k | y_ptr = 0; |
777 | 2.90k | compressed_lines = bytestream2_get_le16(&g2); |
778 | 8.46k | while (compressed_lines > 0) { |
779 | 7.89k | if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk) |
780 | 1.09k | break; |
781 | 6.79k | CHECK_Y_PTR() |
782 | 6.55k | line_packets = sign_extend(bytestream2_get_le16(&g2), 16); |
783 | 6.55k | if (line_packets < 0) { |
784 | 1.64k | line_packets = -line_packets; |
785 | 1.64k | if (line_packets > s->avctx->height) |
786 | 471 | return AVERROR_INVALIDDATA; |
787 | 1.17k | y_ptr += line_packets * s->frame->linesize[0]; |
788 | 4.90k | } else { |
789 | 4.90k | compressed_lines--; |
790 | 4.90k | pixel_ptr = y_ptr; |
791 | 4.90k | CHECK_PIXEL_PTR(0); |
792 | 4.90k | pixel_countdown = s->avctx->width; |
793 | 504k | for (i = 0; i < line_packets; i++) { |
794 | | /* account for the skip bytes */ |
795 | 502k | if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk) |
796 | 904 | break; |
797 | 501k | pixel_skip = bytestream2_get_byte(&g2); |
798 | 501k | pixel_ptr += (pixel_skip*2); /* Pixel is 2 bytes wide */ |
799 | 501k | pixel_countdown -= pixel_skip; |
800 | 501k | byte_run = sign_extend(bytestream2_get_byte(&g2), 8); |
801 | 501k | if (byte_run < 0) { |
802 | 102k | byte_run = -byte_run; |
803 | 102k | pixel = bytestream2_get_le16(&g2); |
804 | 102k | CHECK_PIXEL_PTR(2 * byte_run); |
805 | 5.05M | for (j = 0; j < byte_run; j++, pixel_countdown -= 2) { |
806 | 4.95M | *((signed short*)(&pixels[pixel_ptr])) = pixel; |
807 | 4.95M | pixel_ptr += 2; |
808 | 4.95M | } |
809 | 399k | } else { |
810 | 399k | if (bytestream2_tell(&g2) + 2*byte_run > stream_ptr_after_chunk) |
811 | 1.72k | break; |
812 | 397k | CHECK_PIXEL_PTR(2 * byte_run); |
813 | 2.22M | for (j = 0; j < byte_run; j++, pixel_countdown--) { |
814 | 1.82M | *((signed short*)(&pixels[pixel_ptr])) = bytestream2_get_le16(&g2); |
815 | 1.82M | pixel_ptr += 2; |
816 | 1.82M | } |
817 | 397k | } |
818 | 501k | } |
819 | | |
820 | 4.38k | y_ptr += s->frame->linesize[0]; |
821 | 4.38k | } |
822 | 6.55k | } |
823 | 1.66k | break; |
824 | | |
825 | 1.66k | case FLI_LC: |
826 | 465 | av_log(avctx, AV_LOG_ERROR, "Unexpected FLI_LC chunk in non-palettized FLC\n"); |
827 | 465 | bytestream2_skip(&g2, chunk_size - 6); |
828 | 465 | break; |
829 | | |
830 | 232 | case FLI_BLACK: |
831 | | /* set the whole frame to 0x0000 which is black in both 15Bpp and 16Bpp modes. */ |
832 | 1.42M | for (int y = 0; y < s->avctx->height; y++) |
833 | 1.42M | memset(pixels + y * s->frame->linesize[0], 0, s->avctx->width * 2); |
834 | 232 | break; |
835 | | |
836 | 796 | case FLI_BRUN: |
837 | 796 | y_ptr = 0; |
838 | 1.81M | for (lines = 0; lines < s->avctx->height; lines++) { |
839 | 1.81M | pixel_ptr = y_ptr; |
840 | | /* disregard the line packets; instead, iterate through all |
841 | | * pixels on a row */ |
842 | 1.81M | bytestream2_skip(&g2, 1); |
843 | 1.81M | pixel_countdown = (s->avctx->width * 2); |
844 | | |
845 | 2.78M | while (pixel_countdown > 0) { |
846 | 2.76M | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
847 | 1.78M | break; |
848 | 977k | byte_run = sign_extend(bytestream2_get_byte(&g2), 8); |
849 | 977k | if (byte_run > 0) { |
850 | 364k | palette_idx1 = bytestream2_get_byte(&g2); |
851 | 364k | CHECK_PIXEL_PTR(byte_run); |
852 | 10.6M | for (j = 0; j < byte_run; j++) { |
853 | 10.3M | pixels[pixel_ptr++] = palette_idx1; |
854 | 10.3M | pixel_countdown--; |
855 | 10.3M | if (pixel_countdown < 0) |
856 | 714k | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) (linea%d)\n", |
857 | 714k | pixel_countdown, lines); |
858 | 10.3M | } |
859 | 613k | } else { /* copy bytes if byte_run < 0 */ |
860 | 613k | byte_run = -byte_run; |
861 | 613k | if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk) |
862 | 1.17k | break; |
863 | 612k | CHECK_PIXEL_PTR(byte_run); |
864 | 4.02M | for (j = 0; j < byte_run; j++) { |
865 | 3.40M | palette_idx1 = bytestream2_get_byte(&g2); |
866 | 3.40M | pixels[pixel_ptr++] = palette_idx1; |
867 | 3.40M | pixel_countdown--; |
868 | 3.40M | if (pixel_countdown < 0) |
869 | 298k | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n", |
870 | 298k | pixel_countdown, lines); |
871 | 3.40M | } |
872 | 612k | } |
873 | 977k | } |
874 | | |
875 | | /* Now FLX is strange, in that it is "byte" as opposed to "pixel" run length compressed. |
876 | | * This does not give us any good opportunity to perform word endian conversion |
877 | | * during decompression. So if it is required (i.e., this is not a LE target, we do |
878 | | * a second pass over the line here, swapping the bytes. |
879 | | */ |
880 | | #if HAVE_BIGENDIAN |
881 | | pixel_ptr = y_ptr; |
882 | | pixel_countdown = s->avctx->width; |
883 | | while (pixel_countdown > 0) { |
884 | | *((signed short*)(&pixels[pixel_ptr])) = AV_RL16(&buf[pixel_ptr]); |
885 | | pixel_ptr += 2; |
886 | | } |
887 | | #endif |
888 | 1.81M | y_ptr += s->frame->linesize[0]; |
889 | 1.81M | } |
890 | 390 | break; |
891 | | |
892 | 909 | case FLI_DTA_BRUN: |
893 | 909 | y_ptr = 0; |
894 | 3.03M | for (lines = 0; lines < s->avctx->height; lines++) { |
895 | 3.03M | pixel_ptr = y_ptr; |
896 | | /* disregard the line packets; instead, iterate through all |
897 | | * pixels on a row */ |
898 | 3.03M | bytestream2_skip(&g2, 1); |
899 | 3.03M | pixel_countdown = s->avctx->width; /* Width is in pixels, not bytes */ |
900 | | |
901 | 3.57M | while (pixel_countdown > 0) { |
902 | 3.54M | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
903 | 2.99M | break; |
904 | 545k | byte_run = sign_extend(bytestream2_get_byte(&g2), 8); |
905 | 545k | if (byte_run > 0) { |
906 | 167k | pixel = bytestream2_get_le16(&g2); |
907 | 167k | CHECK_PIXEL_PTR(2 * byte_run); |
908 | 8.26M | for (j = 0; j < byte_run; j++) { |
909 | 8.10M | *((signed short*)(&pixels[pixel_ptr])) = pixel; |
910 | 8.10M | pixel_ptr += 2; |
911 | 8.10M | pixel_countdown--; |
912 | 8.10M | if (pixel_countdown < 0) |
913 | 1.13M | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n", |
914 | 1.13M | pixel_countdown); |
915 | 8.10M | } |
916 | 378k | } else { /* copy pixels if byte_run < 0 */ |
917 | 378k | byte_run = -byte_run; |
918 | 378k | if (bytestream2_tell(&g2) + 2 * byte_run > stream_ptr_after_chunk) |
919 | 1.19k | break; |
920 | 377k | CHECK_PIXEL_PTR(2 * byte_run); |
921 | 2.91M | for (j = 0; j < byte_run; j++) { |
922 | 2.53M | *((signed short*)(&pixels[pixel_ptr])) = bytestream2_get_le16(&g2); |
923 | 2.53M | pixel_ptr += 2; |
924 | 2.53M | pixel_countdown--; |
925 | 2.53M | if (pixel_countdown < 0) |
926 | 405k | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n", |
927 | 405k | pixel_countdown); |
928 | 2.53M | } |
929 | 377k | } |
930 | 545k | } |
931 | | |
932 | 3.03M | y_ptr += s->frame->linesize[0]; |
933 | 3.03M | } |
934 | 488 | break; |
935 | | |
936 | 1.33k | case FLI_COPY: |
937 | 1.57k | case FLI_DTA_COPY: |
938 | | /* copy the chunk (uncompressed frame) */ |
939 | 1.57k | if (chunk_size - 6 > (unsigned int)(FFALIGN(s->avctx->width, 2) * s->avctx->height)*2) { |
940 | 945 | av_log(avctx, AV_LOG_ERROR, "In chunk FLI_COPY : source data (%d bytes) " \ |
941 | 945 | "bigger than image, skipping chunk\n", chunk_size - 6); |
942 | 945 | bytestream2_skip(&g2, chunk_size - 6); |
943 | 945 | } else { |
944 | | |
945 | 628 | if (bytestream2_get_bytes_left(&g2) < 2 * s->avctx->width * s->avctx->height ) |
946 | 383 | return AVERROR_INVALIDDATA; |
947 | 43.9k | for (y_ptr = 0; check_pixel_ptr(y_ptr, 2*s->avctx->width, pixel_limit, direction) == 0; |
948 | 43.7k | y_ptr += s->frame->linesize[0]) { |
949 | | |
950 | 43.7k | pixel_countdown = s->avctx->width; |
951 | 43.7k | pixel_ptr = 0; |
952 | 236k | while (pixel_countdown > 0) { |
953 | 192k | *((signed short*)(&pixels[y_ptr + pixel_ptr])) = bytestream2_get_le16(&g2); |
954 | 192k | pixel_ptr += 2; |
955 | 192k | pixel_countdown--; |
956 | 192k | } |
957 | 43.7k | if (s->avctx->width & 1) |
958 | 43.4k | bytestream2_skip(&g2, 2); |
959 | 43.7k | } |
960 | 245 | } |
961 | 1.19k | break; |
962 | | |
963 | 1.19k | case FLI_MINI: |
964 | | /* some sort of a thumbnail? disregard this chunk... */ |
965 | 421 | bytestream2_skip(&g2, chunk_size - 6); |
966 | 421 | break; |
967 | | |
968 | 2.41k | default: |
969 | 2.41k | av_log(avctx, AV_LOG_ERROR, "Unrecognized chunk type: %d\n", chunk_type); |
970 | 2.41k | break; |
971 | 10.3k | } |
972 | | |
973 | 7.93k | if (stream_ptr_after_chunk - bytestream2_tell(&g2) >= 0) { |
974 | 6.79k | bytestream2_skip(&g2, stream_ptr_after_chunk - bytestream2_tell(&g2)); |
975 | 6.79k | } else { |
976 | 1.13k | av_log(avctx, AV_LOG_ERROR, "Chunk overread\n"); |
977 | 1.13k | break; |
978 | 1.13k | } |
979 | | |
980 | 6.79k | frame_size -= chunk_size; |
981 | 6.79k | num_chunks--; |
982 | 6.79k | } |
983 | | |
984 | | /* by the end of the chunk, the stream ptr should equal the frame |
985 | | * size (minus 1, possibly); if it doesn't, issue a warning */ |
986 | 9.31k | if ((bytestream2_get_bytes_left(&g2) != 0) && (bytestream2_get_bytes_left(&g2) != 1)) |
987 | 1.60k | av_log(avctx, AV_LOG_ERROR, "Processed FLI chunk where chunk size = %d " \ |
988 | 1.60k | "and final chunk ptr = %d\n", buf_size, bytestream2_tell(&g2)); |
989 | | |
990 | 9.31k | if ((ret = av_frame_ref(rframe, s->frame)) < 0) |
991 | 0 | return ret; |
992 | | |
993 | 9.31k | *got_frame = 1; |
994 | | |
995 | 9.31k | return buf_size; |
996 | 9.31k | } |
997 | | |
998 | | static int flic_decode_frame_24BPP(AVCodecContext *avctx, |
999 | | AVFrame *rframe, int *got_frame, |
1000 | | const uint8_t *buf, int buf_size) |
1001 | 11.1k | { |
1002 | 11.1k | FlicDecodeContext *s = avctx->priv_data; |
1003 | | |
1004 | 11.1k | GetByteContext g2; |
1005 | 11.1k | ptrdiff_t pixel_ptr; |
1006 | 11.1k | unsigned char palette_idx1; |
1007 | | |
1008 | 11.1k | unsigned int frame_size; |
1009 | 11.1k | int num_chunks; |
1010 | | |
1011 | 11.1k | unsigned int chunk_size; |
1012 | 11.1k | int chunk_type; |
1013 | | |
1014 | 11.1k | int i, j, ret, direction; |
1015 | | |
1016 | 11.1k | int lines; |
1017 | 11.1k | int compressed_lines; |
1018 | 11.1k | int line_packets; |
1019 | 11.1k | ptrdiff_t y_ptr; |
1020 | 11.1k | int byte_run; |
1021 | 11.1k | int pixel_skip; |
1022 | 11.1k | int pixel_countdown; |
1023 | 11.1k | unsigned char *pixels; |
1024 | 11.1k | int pixel; |
1025 | 11.1k | ptrdiff_t pixel_limit; |
1026 | | |
1027 | 11.1k | bytestream2_init(&g2, buf, buf_size); |
1028 | | |
1029 | 11.1k | if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0) |
1030 | 214 | return ret; |
1031 | | |
1032 | 10.8k | direction = s->frame->linesize[0] > 0; |
1033 | 10.8k | pixels = s->frame->data[0]; |
1034 | 10.8k | pixel_limit = s->avctx->height * s->frame->linesize[0]; |
1035 | | |
1036 | 10.8k | frame_size = bytestream2_get_le32(&g2); |
1037 | 10.8k | bytestream2_skip(&g2, 2); /* skip the magic number */ |
1038 | 10.8k | num_chunks = bytestream2_get_le16(&g2); |
1039 | 10.8k | bytestream2_skip(&g2, 8); /* skip padding */ |
1040 | 10.8k | if (frame_size > buf_size) |
1041 | 9.68k | frame_size = buf_size; |
1042 | | |
1043 | 10.8k | if (frame_size < 16) |
1044 | 1.64k | return AVERROR_INVALIDDATA; |
1045 | 9.24k | frame_size -= 16; |
1046 | | |
1047 | | /* iterate through the chunks */ |
1048 | 15.3k | while ((frame_size > 0) && (num_chunks > 0) && |
1049 | 15.3k | bytestream2_get_bytes_left(&g2) >= 4) { |
1050 | 9.19k | int stream_ptr_after_chunk; |
1051 | 9.19k | chunk_size = bytestream2_get_le32(&g2); |
1052 | 9.19k | if (chunk_size > frame_size) { |
1053 | 6.69k | av_log(avctx, AV_LOG_WARNING, |
1054 | 6.69k | "Invalid chunk_size = %u > frame_size = %u\n", chunk_size, frame_size); |
1055 | 6.69k | chunk_size = frame_size; |
1056 | 6.69k | } |
1057 | 9.19k | stream_ptr_after_chunk = bytestream2_tell(&g2) - 4 + chunk_size; |
1058 | | |
1059 | 9.19k | chunk_type = bytestream2_get_le16(&g2); |
1060 | | |
1061 | | |
1062 | 9.19k | switch (chunk_type) { |
1063 | 641 | case FLI_256_COLOR: |
1064 | 868 | case FLI_COLOR: |
1065 | | /* For some reason, it seems that non-palettized flics do |
1066 | | * include one of these chunks in their first frame. |
1067 | | * Why I do not know, it seems rather extraneous. */ |
1068 | 868 | ff_dlog(avctx, |
1069 | 868 | "Unexpected Palette chunk %d in non-palettized FLC\n", |
1070 | 868 | chunk_type); |
1071 | 868 | bytestream2_skip(&g2, chunk_size - 6); |
1072 | 868 | break; |
1073 | | |
1074 | 2.12k | case FLI_DELTA: |
1075 | 2.32k | case FLI_DTA_LC: |
1076 | 2.32k | y_ptr = 0; |
1077 | 2.32k | compressed_lines = bytestream2_get_le16(&g2); |
1078 | 7.33k | while (compressed_lines > 0) { |
1079 | 6.75k | if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk) |
1080 | 783 | break; |
1081 | 5.97k | CHECK_Y_PTR() |
1082 | 5.73k | line_packets = sign_extend(bytestream2_get_le16(&g2), 16); |
1083 | 5.73k | if (line_packets < 0) { |
1084 | 1.03k | line_packets = -line_packets; |
1085 | 1.03k | if (line_packets > s->avctx->height) |
1086 | 284 | return AVERROR_INVALIDDATA; |
1087 | 747 | y_ptr += line_packets * s->frame->linesize[0]; |
1088 | 4.70k | } else { |
1089 | 4.70k | compressed_lines--; |
1090 | 4.70k | pixel_ptr = y_ptr; |
1091 | 4.70k | CHECK_PIXEL_PTR(0); |
1092 | 4.70k | pixel_countdown = s->avctx->width; |
1093 | 788k | for (i = 0; i < line_packets; i++) { |
1094 | | /* account for the skip bytes */ |
1095 | 786k | if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk) |
1096 | 669 | break; |
1097 | 785k | pixel_skip = bytestream2_get_byte(&g2); |
1098 | 785k | pixel_ptr += (pixel_skip*3); /* Pixel is 3 bytes wide */ |
1099 | 785k | pixel_countdown -= pixel_skip; |
1100 | 785k | byte_run = sign_extend(bytestream2_get_byte(&g2), 8); |
1101 | 785k | if (byte_run < 0) { |
1102 | 208k | byte_run = -byte_run; |
1103 | 208k | pixel = bytestream2_get_le24(&g2); |
1104 | 208k | CHECK_PIXEL_PTR(3 * byte_run); |
1105 | 7.96M | for (j = 0; j < byte_run; j++, pixel_countdown -= 1) { |
1106 | 7.75M | AV_WL24(&pixels[pixel_ptr], pixel); |
1107 | 7.75M | pixel_ptr += 3; |
1108 | 7.75M | } |
1109 | 577k | } else { |
1110 | 577k | if (bytestream2_tell(&g2) + 2*byte_run > stream_ptr_after_chunk) |
1111 | 1.61k | break; |
1112 | 575k | CHECK_PIXEL_PTR(3 * byte_run); |
1113 | 3.22M | for (j = 0; j < byte_run; j++, pixel_countdown--) { |
1114 | 2.65M | pixel = bytestream2_get_le24(&g2); |
1115 | 2.65M | AV_WL24(&pixels[pixel_ptr], pixel); |
1116 | 2.65M | pixel_ptr += 3; |
1117 | 2.65M | } |
1118 | 575k | } |
1119 | 785k | } |
1120 | | |
1121 | 4.25k | y_ptr += s->frame->linesize[0]; |
1122 | 4.25k | } |
1123 | 5.73k | } |
1124 | 1.36k | break; |
1125 | | |
1126 | 1.36k | case FLI_LC: |
1127 | 463 | av_log(avctx, AV_LOG_ERROR, "Unexpected FLI_LC chunk in non-palettized FLC\n"); |
1128 | 463 | bytestream2_skip(&g2, chunk_size - 6); |
1129 | 463 | break; |
1130 | | |
1131 | 272 | case FLI_BLACK: |
1132 | | /* set the whole frame to 0x00 which is black for 24 bit mode. */ |
1133 | 1.55M | for (int y = 0; y < s->avctx->height; y++) |
1134 | 1.55M | memset(pixels + y * s->frame->linesize[0], 0, s->avctx->width * 3); |
1135 | 272 | break; |
1136 | | |
1137 | 998 | case FLI_BRUN: |
1138 | 998 | y_ptr = 0; |
1139 | 2.49M | for (lines = 0; lines < s->avctx->height; lines++) { |
1140 | 2.49M | pixel_ptr = y_ptr; |
1141 | | /* disregard the line packets; instead, iterate through all |
1142 | | * pixels on a row */ |
1143 | 2.49M | bytestream2_skip(&g2, 1); |
1144 | 2.49M | pixel_countdown = (s->avctx->width * 3); |
1145 | | |
1146 | 2.96M | while (pixel_countdown > 0) { |
1147 | 2.96M | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
1148 | 2.48M | break; |
1149 | 471k | byte_run = sign_extend(bytestream2_get_byte(&g2), 8); |
1150 | 471k | if (byte_run > 0) { |
1151 | 179k | palette_idx1 = bytestream2_get_byte(&g2); |
1152 | 179k | CHECK_PIXEL_PTR(byte_run); |
1153 | 5.68M | for (j = 0; j < byte_run; j++) { |
1154 | 5.50M | pixels[pixel_ptr++] = palette_idx1; |
1155 | 5.50M | pixel_countdown--; |
1156 | 5.50M | if (pixel_countdown < 0) |
1157 | 55.5k | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) (linea%d)\n", |
1158 | 55.5k | pixel_countdown, lines); |
1159 | 5.50M | } |
1160 | 292k | } else { /* copy bytes if byte_run < 0 */ |
1161 | 292k | byte_run = -byte_run; |
1162 | 292k | if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk) |
1163 | 942 | break; |
1164 | 291k | CHECK_PIXEL_PTR(byte_run); |
1165 | 3.15M | for (j = 0; j < byte_run; j++) { |
1166 | 2.85M | palette_idx1 = bytestream2_get_byte(&g2); |
1167 | 2.85M | pixels[pixel_ptr++] = palette_idx1; |
1168 | 2.85M | pixel_countdown--; |
1169 | 2.85M | if (pixel_countdown < 0) |
1170 | 17.0k | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n", |
1171 | 17.0k | pixel_countdown, lines); |
1172 | 2.85M | } |
1173 | 290k | } |
1174 | 471k | } |
1175 | | |
1176 | 2.49M | y_ptr += s->frame->linesize[0]; |
1177 | 2.49M | } |
1178 | 538 | break; |
1179 | | |
1180 | 960 | case FLI_DTA_BRUN: |
1181 | 960 | y_ptr = 0; |
1182 | 4.29M | for (lines = 0; lines < s->avctx->height; lines++) { |
1183 | 4.29M | pixel_ptr = y_ptr; |
1184 | | /* disregard the line packets; instead, iterate through all |
1185 | | * pixels on a row */ |
1186 | 4.29M | bytestream2_skip(&g2, 1); |
1187 | 4.29M | pixel_countdown = s->avctx->width; /* Width is in pixels, not bytes */ |
1188 | | |
1189 | 4.60M | while (pixel_countdown > 0) { |
1190 | 4.60M | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
1191 | 4.29M | break; |
1192 | 310k | byte_run = sign_extend(bytestream2_get_byte(&g2), 8); |
1193 | 310k | if (byte_run > 0) { |
1194 | 92.3k | pixel = bytestream2_get_le24(&g2); |
1195 | 92.3k | CHECK_PIXEL_PTR(3 * byte_run); |
1196 | 2.73M | for (j = 0; j < byte_run; j++) { |
1197 | 2.64M | AV_WL24(pixels + pixel_ptr, pixel); |
1198 | 2.64M | pixel_ptr += 3; |
1199 | 2.64M | pixel_countdown--; |
1200 | 2.64M | if (pixel_countdown < 0) |
1201 | 36.5k | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n", |
1202 | 36.5k | pixel_countdown); |
1203 | 2.64M | } |
1204 | 217k | } else { /* copy pixels if byte_run < 0 */ |
1205 | 217k | byte_run = -byte_run; |
1206 | 217k | if (bytestream2_tell(&g2) + 3 * byte_run > stream_ptr_after_chunk) |
1207 | 1.21k | break; |
1208 | 216k | CHECK_PIXEL_PTR(3 * byte_run); |
1209 | 1.22M | for (j = 0; j < byte_run; j++) { |
1210 | 1.00M | pixel = bytestream2_get_le24(&g2); |
1211 | 1.00M | AV_WL24(pixels + pixel_ptr, pixel); |
1212 | 1.00M | pixel_ptr += 3; |
1213 | 1.00M | pixel_countdown--; |
1214 | 1.00M | if (pixel_countdown < 0) |
1215 | 8.18k | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n", |
1216 | 8.18k | pixel_countdown); |
1217 | 1.00M | } |
1218 | 216k | } |
1219 | 310k | } |
1220 | | |
1221 | 4.29M | y_ptr += s->frame->linesize[0]; |
1222 | 4.29M | } |
1223 | 538 | break; |
1224 | | |
1225 | 619 | case FLI_COPY: |
1226 | 844 | case FLI_DTA_COPY: |
1227 | | /* copy the chunk (uncompressed frame) */ |
1228 | 844 | if (chunk_size - 6 > (unsigned int)(FFALIGN(s->avctx->width, 2) * s->avctx->height)*3) { |
1229 | 522 | av_log(avctx, AV_LOG_ERROR, "In chunk FLI_COPY : source data (%d bytes) " \ |
1230 | 522 | "bigger than image, skipping chunk\n", chunk_size - 6); |
1231 | 522 | bytestream2_skip(&g2, chunk_size - 6); |
1232 | 522 | } else { |
1233 | 1.61M | for (y_ptr = 0; check_pixel_ptr(y_ptr, 3*s->avctx->width, pixel_limit, direction) == 0; |
1234 | 1.61M | y_ptr += s->frame->linesize[0]) { |
1235 | | |
1236 | 1.61M | bytestream2_get_buffer(&g2, pixels + y_ptr, 3*s->avctx->width); |
1237 | 1.61M | if (s->avctx->width & 1) |
1238 | 272k | bytestream2_skip(&g2, 3); |
1239 | 1.61M | } |
1240 | 322 | } |
1241 | 844 | break; |
1242 | | |
1243 | 474 | case FLI_MINI: |
1244 | | /* some sort of a thumbnail? disregard this chunk... */ |
1245 | 474 | bytestream2_skip(&g2, chunk_size - 6); |
1246 | 474 | break; |
1247 | | |
1248 | 1.99k | default: |
1249 | 1.99k | av_log(avctx, AV_LOG_ERROR, "Unrecognized chunk type: %d\n", chunk_type); |
1250 | 1.99k | break; |
1251 | 9.19k | } |
1252 | | |
1253 | 7.34k | if (stream_ptr_after_chunk - bytestream2_tell(&g2) >= 0) { |
1254 | 6.12k | bytestream2_skip(&g2, stream_ptr_after_chunk - bytestream2_tell(&g2)); |
1255 | 6.12k | } else { |
1256 | 1.22k | av_log(avctx, AV_LOG_ERROR, "Chunk overread\n"); |
1257 | 1.22k | break; |
1258 | 1.22k | } |
1259 | | |
1260 | 6.12k | frame_size -= chunk_size; |
1261 | 6.12k | num_chunks--; |
1262 | 6.12k | } |
1263 | | |
1264 | | /* by the end of the chunk, the stream ptr should equal the frame |
1265 | | * size (minus 1, possibly); if it doesn't, issue a warning */ |
1266 | 7.39k | if ((bytestream2_get_bytes_left(&g2) != 0) && (bytestream2_get_bytes_left(&g2) != 1)) |
1267 | 916 | av_log(avctx, AV_LOG_ERROR, "Processed FLI chunk where chunk size = %d " \ |
1268 | 916 | "and final chunk ptr = %d\n", buf_size, bytestream2_tell(&g2)); |
1269 | | |
1270 | 7.39k | if ((ret = av_frame_ref(rframe, s->frame)) < 0) |
1271 | 0 | return ret; |
1272 | | |
1273 | 7.39k | *got_frame = 1; |
1274 | | |
1275 | 7.39k | return buf_size; |
1276 | 7.39k | } |
1277 | | |
1278 | | static int flic_decode_frame(AVCodecContext *avctx, AVFrame *frame, |
1279 | | int *got_frame, AVPacket *avpkt) |
1280 | 216k | { |
1281 | 216k | const uint8_t *buf = avpkt->data; |
1282 | 216k | int buf_size = avpkt->size; |
1283 | 216k | if (avctx->pix_fmt == AV_PIX_FMT_MONOBLACK) { |
1284 | 7.40k | return flic_decode_frame_1BPP(avctx, frame, got_frame, |
1285 | 7.40k | buf, buf_size); |
1286 | 209k | } else if (avctx->pix_fmt == AV_PIX_FMT_PAL8) { |
1287 | 185k | return flic_decode_frame_8BPP(avctx, frame, got_frame, |
1288 | 185k | buf, buf_size); |
1289 | 185k | } else if ((avctx->pix_fmt == AV_PIX_FMT_RGB555) || |
1290 | 24.2k | (avctx->pix_fmt == AV_PIX_FMT_RGB565)) { |
1291 | 13.1k | return flic_decode_frame_15_16BPP(avctx, frame, got_frame, |
1292 | 13.1k | buf, buf_size); |
1293 | 13.1k | } else if (avctx->pix_fmt == AV_PIX_FMT_BGR24) { |
1294 | 11.1k | return flic_decode_frame_24BPP(avctx, frame, got_frame, |
1295 | 11.1k | buf, buf_size); |
1296 | 11.1k | } |
1297 | | |
1298 | | /* Should not get here, ever as the pix_fmt is processed */ |
1299 | | /* in flic_decode_init and the above if should deal with */ |
1300 | | /* the finite set of possibilities allowable by here. */ |
1301 | | /* But in case we do, just error out. */ |
1302 | 0 | av_log(avctx, AV_LOG_ERROR, "Unknown FLC format, my science cannot explain how this happened.\n"); |
1303 | 0 | return AVERROR_BUG; |
1304 | 216k | } |
1305 | | |
1306 | | |
1307 | | static av_cold int flic_decode_end(AVCodecContext *avctx) |
1308 | 2.70k | { |
1309 | 2.70k | FlicDecodeContext *s = avctx->priv_data; |
1310 | | |
1311 | 2.70k | av_frame_free(&s->frame); |
1312 | | |
1313 | 2.70k | return 0; |
1314 | 2.70k | } |
1315 | | |
1316 | | const FFCodec ff_flic_decoder = { |
1317 | | .p.name = "flic", |
1318 | | CODEC_LONG_NAME("Autodesk Animator Flic video"), |
1319 | | .p.type = AVMEDIA_TYPE_VIDEO, |
1320 | | .p.id = AV_CODEC_ID_FLIC, |
1321 | | .priv_data_size = sizeof(FlicDecodeContext), |
1322 | | .init = flic_decode_init, |
1323 | | .close = flic_decode_end, |
1324 | | FF_CODEC_DECODE_CB(flic_decode_frame), |
1325 | | .p.capabilities = AV_CODEC_CAP_DR1, |
1326 | | }; |