/src/ffmpeg/libavcodec/flicvideo.c
Line | Count | Source |
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 | 5.07k | #define FLI_256_COLOR 4 |
47 | 8.43k | #define FLI_DELTA 7 |
48 | 4.00k | #define FLI_COLOR 11 |
49 | 7.37k | #define FLI_LC 12 |
50 | 738 | #define FLI_BLACK 13 |
51 | 4.69k | #define FLI_BRUN 15 |
52 | 3.12k | #define FLI_COPY 16 |
53 | 1.14k | #define FLI_MINI 18 |
54 | 1.87k | #define FLI_DTA_BRUN 25 |
55 | 2.08k | #define FLI_DTA_COPY 26 |
56 | 6.31k | #define FLI_DTA_LC 27 |
57 | | |
58 | 1.04k | #define FLI_TYPE_CODE (0xAF11) |
59 | 2.69k | #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.49k | #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 | 10.0M | { |
66 | 10.0M | if (( direction && ptr + n > limit) || |
67 | 10.0M | (!direction && ptr + n < limit)) |
68 | 7.92k | return AVERROR_INVALIDDATA; |
69 | 10.0M | return 0; |
70 | 10.0M | } |
71 | | |
72 | 7.02M | #define CHECK_PIXEL_PTR(n) \ |
73 | 7.02M | { \ |
74 | 7.02M | ret = check_pixel_ptr(pixel_ptr, (n), pixel_limit, direction); \ |
75 | 7.02M | if (ret < 0) \ |
76 | 7.02M | return ret; \ |
77 | 7.02M | } |
78 | | |
79 | 25.6k | #define CHECK_Y_PTR() \ |
80 | 25.6k | { \ |
81 | 25.6k | ret = check_pixel_ptr(y_ptr, 0, pixel_limit, direction); \ |
82 | 25.6k | if (ret < 0) \ |
83 | 25.6k | return ret; \ |
84 | 25.6k | } |
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.74k | { |
97 | 2.74k | FlicDecodeContext *s = avctx->priv_data; |
98 | 2.74k | uint8_t *fli_header = avctx->extradata; |
99 | 2.74k | int depth; |
100 | | |
101 | 2.74k | if (avctx->extradata_size != 0 && |
102 | 1.70k | avctx->extradata_size != 12 && |
103 | 1.69k | avctx->extradata_size != 128 && |
104 | 53 | avctx->extradata_size != 256 && |
105 | 52 | avctx->extradata_size != 904 && |
106 | 51 | avctx->extradata_size != 1024) { |
107 | 49 | av_log(avctx, AV_LOG_ERROR, "Unexpected extradata size %d\n", avctx->extradata_size); |
108 | 49 | return AVERROR_INVALIDDATA; |
109 | 49 | } |
110 | | |
111 | 2.69k | s->avctx = avctx; |
112 | | |
113 | 2.69k | 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.69k | } 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.68k | } else if (avctx->extradata_size == 0 || |
128 | 1.64k | avctx->extradata_size == 256 || |
129 | | /* see FFmpeg ticket #1234 */ |
130 | 1.64k | avctx->extradata_size == 904) { |
131 | 1.04k | s->fli_type = FLI_TYPE_CODE; |
132 | 1.04k | depth = 8; |
133 | 1.64k | } else { |
134 | 1.64k | s->fli_type = AV_RL16(&fli_header[4]); |
135 | 1.64k | depth = AV_RL16(&fli_header[12]); |
136 | 1.64k | } |
137 | | |
138 | 2.69k | if (depth == 0) { |
139 | 119 | depth = 8; /* Some FLC generators set depth to zero, when they mean 8Bpp. Fix up here */ |
140 | 119 | } |
141 | | |
142 | 2.69k | 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.69k | switch (depth) { |
147 | 344 | case 1 : avctx->pix_fmt = AV_PIX_FMT_MONOBLACK; break; |
148 | 1.17k | case 8 : avctx->pix_fmt = AV_PIX_FMT_PAL8; break; |
149 | 135 | case 15 : avctx->pix_fmt = AV_PIX_FMT_RGB555; break; |
150 | 454 | case 16 : avctx->pix_fmt = AV_PIX_FMT_RGB565; break; |
151 | 588 | case 24 : avctx->pix_fmt = AV_PIX_FMT_BGR24; break; |
152 | 5 | default : |
153 | 5 | av_log(avctx, AV_LOG_ERROR, "Unknown FLC/FLX depth of %d Bpp is unsupported.\n",depth); |
154 | 5 | return AVERROR_INVALIDDATA; |
155 | 2.69k | } |
156 | | |
157 | 2.69k | s->frame = av_frame_alloc(); |
158 | 2.69k | if (!s->frame) |
159 | 0 | return AVERROR(ENOMEM); |
160 | | |
161 | 2.69k | s->new_palette = 0; |
162 | | |
163 | 2.69k | return 0; |
164 | 2.69k | } |
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 | 8.40k | { |
170 | 8.40k | FlicDecodeContext *s = avctx->priv_data; |
171 | | |
172 | 8.40k | GetByteContext g2; |
173 | 8.40k | ptrdiff_t pixel_ptr; |
174 | | |
175 | 8.40k | unsigned int frame_size; |
176 | 8.40k | int num_chunks; |
177 | | |
178 | 8.40k | unsigned int chunk_size; |
179 | 8.40k | int chunk_type; |
180 | | |
181 | 8.40k | int i, j, ret, direction; |
182 | | |
183 | 8.40k | int lines; |
184 | 8.40k | int compressed_lines; |
185 | 8.40k | int starting_line; |
186 | 8.40k | int line_packets; |
187 | 8.40k | ptrdiff_t y_ptr; |
188 | 8.40k | int byte_run; |
189 | 8.40k | int pixel_skip; |
190 | 8.40k | int pixel_countdown; |
191 | 8.40k | unsigned char *pixels; |
192 | 8.40k | ptrdiff_t pixel_limit; |
193 | | |
194 | 8.40k | bytestream2_init(&g2, buf, buf_size); |
195 | | |
196 | 8.40k | if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0) |
197 | 214 | return ret; |
198 | | |
199 | 8.19k | direction = s->frame->linesize[0] > 0; |
200 | 8.19k | pixels = s->frame->data[0]; |
201 | 8.19k | pixel_limit = s->avctx->height * s->frame->linesize[0]; |
202 | 8.19k | if (buf_size < 16 || buf_size > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE) |
203 | 675 | return AVERROR_INVALIDDATA; |
204 | 7.51k | frame_size = bytestream2_get_le32(&g2); |
205 | 7.51k | if (frame_size > buf_size) |
206 | 7.25k | frame_size = buf_size; |
207 | 7.51k | bytestream2_skip(&g2, 2); /* skip the magic number */ |
208 | 7.51k | num_chunks = bytestream2_get_le16(&g2); |
209 | 7.51k | bytestream2_skip(&g2, 8); /* skip padding */ |
210 | | |
211 | 7.51k | if (frame_size < 16) |
212 | 255 | return AVERROR_INVALIDDATA; |
213 | | |
214 | 7.26k | frame_size -= 16; |
215 | | |
216 | | /* iterate through the chunks */ |
217 | 11.3k | while ((frame_size >= 6) && (num_chunks > 0) && |
218 | 6.39k | bytestream2_get_bytes_left(&g2) >= 4) { |
219 | 6.39k | int stream_ptr_after_chunk; |
220 | 6.39k | chunk_size = bytestream2_get_le32(&g2); |
221 | 6.39k | if (chunk_size > frame_size) { |
222 | 5.44k | av_log(avctx, AV_LOG_WARNING, |
223 | 5.44k | "Invalid chunk_size = %u > frame_size = %u\n", chunk_size, frame_size); |
224 | 5.44k | chunk_size = frame_size; |
225 | 5.44k | } |
226 | 6.39k | stream_ptr_after_chunk = bytestream2_tell(&g2) - 4 + chunk_size; |
227 | | |
228 | 6.39k | chunk_type = bytestream2_get_le16(&g2); |
229 | | |
230 | 6.39k | switch (chunk_type) { |
231 | 1.16k | 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.16k | y_ptr = 0; |
235 | 3.35M | for (lines = 0; lines < s->avctx->height; lines++) { |
236 | 3.35M | pixel_ptr = y_ptr; |
237 | | /* disregard the line packets; instead, iterate through all |
238 | | * pixels on a row */ |
239 | 3.35M | bytestream2_skip(&g2, 1); |
240 | 3.35M | pixel_countdown = (s->avctx->width + 7) >> 3; |
241 | 3.68M | while (pixel_countdown > 0) { |
242 | 3.41M | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
243 | 3.08M | break; |
244 | 330k | byte_run = sign_extend(bytestream2_get_byte(&g2), 8); |
245 | 330k | if (!byte_run) { |
246 | 298 | av_log(avctx, AV_LOG_ERROR, "Invalid byte run value.\n"); |
247 | 298 | return AVERROR_INVALIDDATA; |
248 | 298 | } |
249 | | |
250 | 330k | if (byte_run > 0) { |
251 | 323k | int value = bytestream2_get_byte(&g2); |
252 | 323k | CHECK_PIXEL_PTR(byte_run); |
253 | 25.3M | for (j = 0; j < byte_run; j++) { |
254 | 25.0M | pixels[pixel_ptr++] = value; |
255 | 25.0M | pixel_countdown--; |
256 | 25.0M | if (pixel_countdown < 0) |
257 | 16.2M | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n", |
258 | 16.2M | pixel_countdown, lines); |
259 | 25.0M | } |
260 | 323k | } else { /* copy bytes if byte_run < 0 */ |
261 | 6.62k | byte_run = -byte_run; |
262 | 6.62k | CHECK_PIXEL_PTR(byte_run); |
263 | 6.38k | if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk) |
264 | 639 | break; |
265 | 41.1k | for (j = 0; j < byte_run; j++) { |
266 | 35.4k | pixels[pixel_ptr++] = bytestream2_get_byte(&g2); |
267 | 35.4k | pixel_countdown--; |
268 | 35.4k | if (pixel_countdown < 0) |
269 | 17.9k | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n", |
270 | 17.9k | pixel_countdown, lines); |
271 | 35.4k | } |
272 | 5.74k | } |
273 | 330k | } |
274 | | |
275 | 3.35M | y_ptr += s->frame->linesize[0]; |
276 | 3.35M | } |
277 | 418 | break; |
278 | | |
279 | 3.21k | case FLI_LC: |
280 | | /* line compressed */ |
281 | 3.21k | starting_line = bytestream2_get_le16(&g2); |
282 | 3.21k | if (starting_line >= s->avctx->height) |
283 | 292 | return AVERROR_INVALIDDATA; |
284 | 2.92k | y_ptr = 0; |
285 | 2.92k | y_ptr += starting_line * s->frame->linesize[0]; |
286 | | |
287 | 2.92k | compressed_lines = bytestream2_get_le16(&g2); |
288 | 211k | while (compressed_lines > 0) { |
289 | 210k | pixel_ptr = y_ptr; |
290 | 210k | CHECK_PIXEL_PTR(0); |
291 | 210k | pixel_countdown = (s->avctx->width + 7) >> 3; |
292 | 210k | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
293 | 1.58k | break; |
294 | 209k | line_packets = bytestream2_get_byte(&g2); |
295 | 209k | if (line_packets > 0) { |
296 | 1.25M | for (i = 0; i < line_packets; i++) { |
297 | | /* account for the skip bytes */ |
298 | 1.24M | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
299 | 1.63k | break; |
300 | 1.23M | pixel_skip = bytestream2_get_byte(&g2); |
301 | 1.23M | pixel_ptr += pixel_skip; |
302 | 1.23M | pixel_countdown -= pixel_skip; |
303 | 1.23M | byte_run = sign_extend(bytestream2_get_byte(&g2),8); |
304 | 1.23M | if (byte_run > 0) { |
305 | 255k | CHECK_PIXEL_PTR(byte_run); |
306 | 255k | if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk) |
307 | 2.22k | break; |
308 | 5.09M | for (j = 0; j < byte_run; j++, pixel_countdown--) { |
309 | 4.84M | pixels[pixel_ptr++] = bytestream2_get_byte(&g2); |
310 | 4.84M | } |
311 | 983k | } else if (byte_run < 0) { |
312 | 356k | int value = bytestream2_get_byte(&g2); |
313 | 356k | byte_run = -byte_run; |
314 | 356k | CHECK_PIXEL_PTR(byte_run); |
315 | 17.7M | for (j = 0; j < byte_run; j++, pixel_countdown--) { |
316 | 17.3M | pixels[pixel_ptr++] = value; |
317 | 17.3M | } |
318 | 355k | } |
319 | 1.23M | } |
320 | 18.9k | } |
321 | | |
322 | 208k | y_ptr += s->frame->linesize[0]; |
323 | 208k | compressed_lines--; |
324 | 208k | } |
325 | 2.01k | break; |
326 | | |
327 | 2.01k | default: |
328 | 2.00k | av_log(avctx, AV_LOG_ERROR, "Unrecognized chunk type: %d\n", chunk_type); |
329 | 2.00k | break; |
330 | 6.39k | } |
331 | | |
332 | 4.44k | if (stream_ptr_after_chunk - bytestream2_tell(&g2) >= 0) { |
333 | 4.08k | bytestream2_skip(&g2, stream_ptr_after_chunk - bytestream2_tell(&g2)); |
334 | 4.08k | } else { |
335 | 360 | av_log(avctx, AV_LOG_ERROR, "Chunk overread\n"); |
336 | 360 | break; |
337 | 360 | } |
338 | | |
339 | 4.08k | frame_size -= chunk_size; |
340 | 4.08k | num_chunks--; |
341 | 4.08k | } |
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.31k | if (bytestream2_get_bytes_left(&g2) > 2) |
346 | 824 | av_log(avctx, AV_LOG_ERROR, "Processed FLI chunk where chunk size = %d " \ |
347 | 824 | "and final chunk ptr = %d\n", buf_size, |
348 | 824 | buf_size - bytestream2_get_bytes_left(&g2)); |
349 | | |
350 | 5.31k | if ((ret = av_frame_ref(rframe, s->frame)) < 0) |
351 | 0 | return ret; |
352 | | |
353 | 5.31k | *got_frame = 1; |
354 | | |
355 | 5.31k | return buf_size; |
356 | 5.31k | } |
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 | 33.5k | { |
362 | 33.5k | FlicDecodeContext *s = avctx->priv_data; |
363 | | |
364 | 33.5k | GetByteContext g2; |
365 | 33.5k | ptrdiff_t pixel_ptr; |
366 | 33.5k | int palette_ptr; |
367 | 33.5k | unsigned char palette_idx1; |
368 | 33.5k | unsigned char palette_idx2; |
369 | | |
370 | 33.5k | unsigned int frame_size; |
371 | 33.5k | int num_chunks; |
372 | | |
373 | 33.5k | unsigned int chunk_size; |
374 | 33.5k | int chunk_type; |
375 | | |
376 | 33.5k | int i, j, ret, direction; |
377 | | |
378 | 33.5k | int color_packets; |
379 | 33.5k | int color_changes; |
380 | 33.5k | int color_shift; |
381 | 33.5k | unsigned char r, g, b; |
382 | | |
383 | 33.5k | int lines; |
384 | 33.5k | int compressed_lines; |
385 | 33.5k | int starting_line; |
386 | 33.5k | int line_packets; |
387 | 33.5k | ptrdiff_t y_ptr; |
388 | 33.5k | int byte_run; |
389 | 33.5k | int pixel_skip; |
390 | 33.5k | int pixel_countdown; |
391 | 33.5k | unsigned char *pixels; |
392 | 33.5k | ptrdiff_t pixel_limit; |
393 | | |
394 | 33.5k | bytestream2_init(&g2, buf, buf_size); |
395 | | |
396 | 33.5k | if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0) |
397 | 5.35k | return ret; |
398 | | |
399 | 28.1k | direction = s->frame->linesize[0] > 0; |
400 | 28.1k | pixels = s->frame->data[0]; |
401 | 28.1k | pixel_limit = s->avctx->height * s->frame->linesize[0]; |
402 | 28.1k | if (buf_size < 16 || buf_size > INT_MAX - (3 * 256 + AV_INPUT_BUFFER_PADDING_SIZE)) |
403 | 3.59k | return AVERROR_INVALIDDATA; |
404 | 24.5k | frame_size = bytestream2_get_le32(&g2); |
405 | 24.5k | if (frame_size > buf_size) |
406 | 24.2k | frame_size = buf_size; |
407 | 24.5k | bytestream2_skip(&g2, 2); /* skip the magic number */ |
408 | 24.5k | num_chunks = bytestream2_get_le16(&g2); |
409 | 24.5k | bytestream2_skip(&g2, 8); /* skip padding */ |
410 | | |
411 | 24.5k | if (frame_size < 16) |
412 | 285 | return AVERROR_INVALIDDATA; |
413 | | |
414 | 24.2k | frame_size -= 16; |
415 | | |
416 | | /* iterate through the chunks */ |
417 | 33.3k | while ((frame_size >= 6) && (num_chunks > 0) && |
418 | 13.2k | bytestream2_get_bytes_left(&g2) >= 4) { |
419 | 13.2k | int stream_ptr_after_chunk; |
420 | 13.2k | chunk_size = bytestream2_get_le32(&g2); |
421 | 13.2k | if (chunk_size > frame_size) { |
422 | 11.1k | av_log(avctx, AV_LOG_WARNING, |
423 | 11.1k | "Invalid chunk_size = %u > frame_size = %u\n", chunk_size, frame_size); |
424 | 11.1k | chunk_size = frame_size; |
425 | 11.1k | } |
426 | 13.2k | stream_ptr_after_chunk = bytestream2_tell(&g2) - 4 + chunk_size; |
427 | | |
428 | 13.2k | chunk_type = bytestream2_get_le16(&g2); |
429 | | |
430 | 13.2k | switch (chunk_type) { |
431 | 1.48k | case FLI_256_COLOR: |
432 | 2.31k | 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 | 2.31k | if ((chunk_type == FLI_256_COLOR) && (s->fli_type != FLC_MAGIC_CARPET_SYNTHETIC_TYPE_CODE)) |
438 | 1.28k | color_shift = 0; |
439 | 1.02k | else |
440 | 1.02k | color_shift = 2; |
441 | | /* set up the palette */ |
442 | 2.31k | color_packets = bytestream2_get_le16(&g2); |
443 | 2.31k | palette_ptr = 0; |
444 | 104k | for (i = 0; i < color_packets; i++) { |
445 | | /* first byte is how many colors to skip */ |
446 | 102k | palette_ptr += bytestream2_get_byte(&g2); |
447 | | |
448 | | /* next byte indicates how many entries to change */ |
449 | 102k | color_changes = bytestream2_get_byte(&g2); |
450 | | |
451 | | /* if there are 0 color changes, there are actually 256 */ |
452 | 102k | if (color_changes == 0) |
453 | 5.24k | color_changes = 256; |
454 | | |
455 | 102k | if (bytestream2_tell(&g2) + color_changes * 3 > stream_ptr_after_chunk) |
456 | 1.18k | break; |
457 | | |
458 | 2.04M | for (j = 0; j < color_changes; j++) { |
459 | 1.94M | unsigned int entry; |
460 | | |
461 | | /* wrap around, for good measure */ |
462 | 1.94M | if ((unsigned)palette_ptr >= 256) |
463 | 9.54k | palette_ptr = 0; |
464 | | |
465 | 1.94M | r = bytestream2_get_byte(&g2) << color_shift; |
466 | 1.94M | g = bytestream2_get_byte(&g2) << color_shift; |
467 | 1.94M | b = bytestream2_get_byte(&g2) << color_shift; |
468 | 1.94M | entry = 0xFFU << 24 | r << 16 | g << 8 | b; |
469 | 1.94M | if (color_shift == 2) |
470 | 2.58k | entry |= entry >> 6 & 0x30303; |
471 | 1.94M | if (s->palette[palette_ptr] != entry) |
472 | 1.68M | s->new_palette = 1; |
473 | 1.94M | s->palette[palette_ptr++] = entry; |
474 | 1.94M | } |
475 | 101k | } |
476 | 2.31k | break; |
477 | | |
478 | 2.85k | case FLI_DELTA: |
479 | 2.85k | y_ptr = 0; |
480 | 2.85k | compressed_lines = bytestream2_get_le16(&g2); |
481 | 13.9k | while (compressed_lines > 0) { |
482 | 13.4k | if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk) |
483 | 987 | break; |
484 | 12.4k | CHECK_Y_PTR() |
485 | 12.1k | line_packets = sign_extend(bytestream2_get_le16(&g2), 16); |
486 | 12.1k | if ((line_packets & 0xC000) == 0xC000) { |
487 | | // line skip opcode |
488 | 3.41k | line_packets = -line_packets; |
489 | 3.41k | if (line_packets > s->avctx->height) |
490 | 285 | return AVERROR_INVALIDDATA; |
491 | 3.12k | y_ptr += line_packets * s->frame->linesize[0]; |
492 | 8.69k | } else if ((line_packets & 0xC000) == 0x4000) { |
493 | 1.52k | av_log(avctx, AV_LOG_ERROR, "Undefined opcode (%x) in DELTA_FLI\n", line_packets); |
494 | 7.17k | } else if ((line_packets & 0xC000) == 0x8000) { |
495 | | // "last byte" opcode |
496 | 1.37k | pixel_ptr= y_ptr + s->frame->linesize[0] - 1; |
497 | 1.37k | CHECK_PIXEL_PTR(0); |
498 | 1.16k | pixels[pixel_ptr] = line_packets & 0xff; |
499 | 5.79k | } else { |
500 | 5.79k | compressed_lines--; |
501 | 5.79k | pixel_ptr = y_ptr; |
502 | 5.79k | CHECK_PIXEL_PTR(0); |
503 | 5.79k | pixel_countdown = s->avctx->width; |
504 | 495k | for (i = 0; i < line_packets; i++) { |
505 | 492k | if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk) |
506 | 731 | break; |
507 | | /* account for the skip bytes */ |
508 | 491k | pixel_skip = bytestream2_get_byte(&g2); |
509 | 491k | pixel_ptr += pixel_skip; |
510 | 491k | pixel_countdown -= pixel_skip; |
511 | 491k | byte_run = sign_extend(bytestream2_get_byte(&g2), 8); |
512 | 491k | if (byte_run < 0) { |
513 | 111k | byte_run = -byte_run; |
514 | 111k | palette_idx1 = bytestream2_get_byte(&g2); |
515 | 111k | palette_idx2 = bytestream2_get_byte(&g2); |
516 | 111k | CHECK_PIXEL_PTR(byte_run * 2); |
517 | 3.53M | for (j = 0; j < byte_run; j++, pixel_countdown -= 2) { |
518 | 3.42M | pixels[pixel_ptr++] = palette_idx1; |
519 | 3.42M | pixels[pixel_ptr++] = palette_idx2; |
520 | 3.42M | } |
521 | 379k | } else { |
522 | 379k | CHECK_PIXEL_PTR(byte_run * 2); |
523 | 379k | if (bytestream2_tell(&g2) + byte_run * 2 > stream_ptr_after_chunk) |
524 | 1.09k | break; |
525 | 3.30M | for (j = 0; j < byte_run * 2; j++, pixel_countdown--) { |
526 | 2.92M | pixels[pixel_ptr++] = bytestream2_get_byte(&g2); |
527 | 2.92M | } |
528 | 378k | } |
529 | 491k | } |
530 | | |
531 | 5.29k | y_ptr += s->frame->linesize[0]; |
532 | 5.29k | } |
533 | 12.1k | } |
534 | 1.54k | break; |
535 | | |
536 | 2.15k | case FLI_LC: |
537 | | /* line compressed */ |
538 | 2.15k | starting_line = bytestream2_get_le16(&g2); |
539 | 2.15k | if (starting_line >= s->avctx->height) |
540 | 268 | return AVERROR_INVALIDDATA; |
541 | 1.88k | y_ptr = 0; |
542 | 1.88k | y_ptr += starting_line * s->frame->linesize[0]; |
543 | | |
544 | 1.88k | compressed_lines = bytestream2_get_le16(&g2); |
545 | 376k | while (compressed_lines > 0) { |
546 | 376k | pixel_ptr = y_ptr; |
547 | 376k | CHECK_PIXEL_PTR(0); |
548 | 376k | pixel_countdown = s->avctx->width; |
549 | 376k | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
550 | 748 | break; |
551 | 375k | line_packets = bytestream2_get_byte(&g2); |
552 | 375k | if (line_packets > 0) { |
553 | 1.08M | for (i = 0; i < line_packets; i++) { |
554 | | /* account for the skip bytes */ |
555 | 1.07M | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
556 | 800 | break; |
557 | 1.07M | pixel_skip = bytestream2_get_byte(&g2); |
558 | 1.07M | pixel_ptr += pixel_skip; |
559 | 1.07M | pixel_countdown -= pixel_skip; |
560 | 1.07M | byte_run = sign_extend(bytestream2_get_byte(&g2),8); |
561 | 1.07M | if (byte_run > 0) { |
562 | 223k | CHECK_PIXEL_PTR(byte_run); |
563 | 223k | if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk) |
564 | 1.56k | break; |
565 | 4.24M | for (j = 0; j < byte_run; j++, pixel_countdown--) { |
566 | 4.02M | pixels[pixel_ptr++] = bytestream2_get_byte(&g2); |
567 | 4.02M | } |
568 | 847k | } else if (byte_run < 0) { |
569 | 277k | byte_run = -byte_run; |
570 | 277k | palette_idx1 = bytestream2_get_byte(&g2); |
571 | 277k | CHECK_PIXEL_PTR(byte_run); |
572 | 13.3M | for (j = 0; j < byte_run; j++, pixel_countdown--) { |
573 | 13.0M | pixels[pixel_ptr++] = palette_idx1; |
574 | 13.0M | } |
575 | 277k | } |
576 | 1.07M | } |
577 | 15.6k | } |
578 | | |
579 | 374k | y_ptr += s->frame->linesize[0]; |
580 | 374k | compressed_lines--; |
581 | 374k | } |
582 | 1.17k | break; |
583 | | |
584 | 1.17k | case FLI_BLACK: |
585 | | /* set the whole frame to color 0 (which is usually black) */ |
586 | 3.96M | for (int y = 0; y < s->avctx->height; y++) |
587 | 3.96M | memset(pixels + y * s->frame->linesize[0], 0, s->avctx->width); |
588 | 225 | break; |
589 | | |
590 | 1.47k | 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.47k | y_ptr = 0; |
594 | 3.23M | for (lines = 0; lines < s->avctx->height; lines++) { |
595 | 3.23M | pixel_ptr = y_ptr; |
596 | | /* disregard the line packets; instead, iterate through all |
597 | | * pixels on a row */ |
598 | 3.23M | bytestream2_skip(&g2, 1); |
599 | 3.23M | pixel_countdown = s->avctx->width; |
600 | 4.04M | while (pixel_countdown > 0) { |
601 | 3.89M | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
602 | 3.08M | break; |
603 | 808k | byte_run = sign_extend(bytestream2_get_byte(&g2), 8); |
604 | 808k | if (!byte_run) { |
605 | 424 | av_log(avctx, AV_LOG_ERROR, "Invalid byte run value.\n"); |
606 | 424 | return AVERROR_INVALIDDATA; |
607 | 424 | } |
608 | | |
609 | 807k | if (byte_run > 0) { |
610 | 800k | palette_idx1 = bytestream2_get_byte(&g2); |
611 | 800k | CHECK_PIXEL_PTR(byte_run); |
612 | 25.9M | for (j = 0; j < byte_run; j++) { |
613 | 25.1M | pixels[pixel_ptr++] = palette_idx1; |
614 | 25.1M | pixel_countdown--; |
615 | 25.1M | if (pixel_countdown < 0) |
616 | 5.35M | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n", |
617 | 5.35M | pixel_countdown, lines); |
618 | 25.1M | } |
619 | 800k | } else { /* copy bytes if byte_run < 0 */ |
620 | 6.67k | byte_run = -byte_run; |
621 | 6.67k | CHECK_PIXEL_PTR(byte_run); |
622 | 6.43k | if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk) |
623 | 1.43k | break; |
624 | 58.5k | for (j = 0; j < byte_run; j++) { |
625 | 53.5k | pixels[pixel_ptr++] = bytestream2_get_byte(&g2); |
626 | 53.5k | pixel_countdown--; |
627 | 53.5k | if (pixel_countdown < 0) |
628 | 5.44k | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n", |
629 | 5.44k | pixel_countdown, lines); |
630 | 53.5k | } |
631 | 5.00k | } |
632 | 807k | } |
633 | | |
634 | 3.23M | y_ptr += s->frame->linesize[0]; |
635 | 3.23M | } |
636 | 617 | break; |
637 | | |
638 | 1.53k | case FLI_COPY: |
639 | | /* copy the chunk (uncompressed frame) */ |
640 | 1.53k | if (chunk_size - 6 != FFALIGN(s->avctx->width, 4) * s->avctx->height) { |
641 | 884 | av_log(avctx, AV_LOG_ERROR, "In chunk FLI_COPY : source data (%d bytes) " \ |
642 | 884 | "has incorrect size, skipping chunk\n", chunk_size - 6); |
643 | 884 | bytestream2_skip(&g2, chunk_size - 6); |
644 | 884 | } else { |
645 | 2.74k | for (y_ptr = 0; check_pixel_ptr(y_ptr, s->avctx->width, pixel_limit, direction) == 0; |
646 | 2.09k | y_ptr += s->frame->linesize[0]) { |
647 | 2.09k | bytestream2_get_buffer(&g2, &pixels[y_ptr], |
648 | 2.09k | s->avctx->width); |
649 | 2.09k | if (s->avctx->width & 3) |
650 | 1.15k | bytestream2_skip(&g2, 4 - (s->avctx->width & 3)); |
651 | 2.09k | } |
652 | 649 | } |
653 | 1.53k | break; |
654 | | |
655 | 249 | case FLI_MINI: |
656 | | /* some sort of a thumbnail? disregard this chunk... */ |
657 | 249 | break; |
658 | | |
659 | 2.43k | default: |
660 | 2.43k | av_log(avctx, AV_LOG_ERROR, "Unrecognized chunk type: %d\n", chunk_type); |
661 | 2.43k | break; |
662 | 13.2k | } |
663 | | |
664 | 10.0k | if (stream_ptr_after_chunk - bytestream2_tell(&g2) >= 0) { |
665 | 9.08k | bytestream2_skip(&g2, stream_ptr_after_chunk - bytestream2_tell(&g2)); |
666 | 9.08k | } else { |
667 | 997 | av_log(avctx, AV_LOG_ERROR, "Chunk overread\n"); |
668 | 997 | break; |
669 | 997 | } |
670 | | |
671 | 9.08k | frame_size -= chunk_size; |
672 | 9.08k | num_chunks--; |
673 | 9.08k | } |
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 | 21.1k | if (bytestream2_get_bytes_left(&g2) > 2) |
678 | 3.03k | av_log(avctx, AV_LOG_ERROR, "Processed FLI chunk where chunk size = %d " \ |
679 | 3.03k | "and final chunk ptr = %d\n", buf_size, |
680 | 3.03k | buf_size - bytestream2_get_bytes_left(&g2)); |
681 | | |
682 | | /* make the palette available on the way out */ |
683 | 21.1k | memcpy(s->frame->data[1], s->palette, AVPALETTE_SIZE); |
684 | 21.1k | if (s->new_palette) { |
685 | 659 | s->new_palette = 0; |
686 | 659 | } |
687 | | |
688 | 21.1k | if ((ret = av_frame_ref(rframe, s->frame)) < 0) |
689 | 0 | return ret; |
690 | | |
691 | 21.1k | *got_frame = 1; |
692 | | |
693 | 21.1k | return buf_size; |
694 | 21.1k | } |
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 | 78.2k | { |
700 | | /* Note, the only difference between the 15Bpp and 16Bpp */ |
701 | | /* Format is the pixel format, the packets are processed the same. */ |
702 | 78.2k | FlicDecodeContext *s = avctx->priv_data; |
703 | | |
704 | 78.2k | GetByteContext g2; |
705 | 78.2k | ptrdiff_t pixel_ptr; |
706 | 78.2k | unsigned char palette_idx1; |
707 | | |
708 | 78.2k | unsigned int frame_size; |
709 | 78.2k | int num_chunks; |
710 | | |
711 | 78.2k | unsigned int chunk_size; |
712 | 78.2k | int chunk_type; |
713 | | |
714 | 78.2k | int i, j, ret, direction; |
715 | | |
716 | 78.2k | int lines; |
717 | 78.2k | int compressed_lines; |
718 | 78.2k | int line_packets; |
719 | 78.2k | ptrdiff_t y_ptr; |
720 | 78.2k | int byte_run; |
721 | 78.2k | int pixel_skip; |
722 | 78.2k | int pixel_countdown; |
723 | 78.2k | unsigned char *pixels; |
724 | 78.2k | int pixel; |
725 | 78.2k | ptrdiff_t pixel_limit; |
726 | | |
727 | 78.2k | bytestream2_init(&g2, buf, buf_size); |
728 | | |
729 | 78.2k | if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0) |
730 | 334 | return ret; |
731 | | |
732 | 77.9k | direction = s->frame->linesize[0] > 0; |
733 | 77.9k | pixels = s->frame->data[0]; |
734 | 77.9k | pixel_limit = s->avctx->height * s->frame->linesize[0]; |
735 | | |
736 | 77.9k | frame_size = bytestream2_get_le32(&g2); |
737 | 77.9k | bytestream2_skip(&g2, 2); /* skip the magic number */ |
738 | 77.9k | num_chunks = bytestream2_get_le16(&g2); |
739 | 77.9k | bytestream2_skip(&g2, 8); /* skip padding */ |
740 | 77.9k | if (frame_size > buf_size) |
741 | 74.0k | frame_size = buf_size; |
742 | | |
743 | 77.9k | if (frame_size < 16) |
744 | 4.13k | return AVERROR_INVALIDDATA; |
745 | 73.7k | frame_size -= 16; |
746 | | |
747 | | /* iterate through the chunks */ |
748 | 84.3k | while ((frame_size > 0) && (num_chunks > 0) && |
749 | 31.2k | bytestream2_get_bytes_left(&g2) >= 4) { |
750 | 14.2k | int stream_ptr_after_chunk; |
751 | 14.2k | chunk_size = bytestream2_get_le32(&g2); |
752 | 14.2k | if (chunk_size > frame_size) { |
753 | 10.1k | av_log(avctx, AV_LOG_WARNING, |
754 | 10.1k | "Invalid chunk_size = %u > frame_size = %u\n", chunk_size, frame_size); |
755 | 10.1k | chunk_size = frame_size; |
756 | 10.1k | } |
757 | 14.2k | stream_ptr_after_chunk = bytestream2_tell(&g2) - 4 + chunk_size; |
758 | | |
759 | 14.2k | chunk_type = bytestream2_get_le16(&g2); |
760 | | |
761 | | |
762 | 14.2k | switch (chunk_type) { |
763 | 607 | case FLI_256_COLOR: |
764 | 817 | 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 | 817 | ff_dlog(avctx, |
769 | 817 | "Unexpected Palette chunk %d in non-palettized FLC\n", |
770 | 817 | chunk_type); |
771 | 817 | bytestream2_skip(&g2, chunk_size - 6); |
772 | 817 | break; |
773 | | |
774 | 3.44k | case FLI_DELTA: |
775 | 3.96k | case FLI_DTA_LC: |
776 | 3.96k | y_ptr = 0; |
777 | 3.96k | compressed_lines = bytestream2_get_le16(&g2); |
778 | 9.63k | while (compressed_lines > 0) { |
779 | 7.65k | if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk) |
780 | 784 | break; |
781 | 6.87k | CHECK_Y_PTR() |
782 | 6.58k | line_packets = sign_extend(bytestream2_get_le16(&g2), 16); |
783 | 6.58k | if (line_packets < 0) { |
784 | 1.31k | line_packets = -line_packets; |
785 | 1.31k | if (line_packets > s->avctx->height) |
786 | 436 | return AVERROR_INVALIDDATA; |
787 | 883 | y_ptr += line_packets * s->frame->linesize[0]; |
788 | 5.26k | } else { |
789 | 5.26k | compressed_lines--; |
790 | 5.26k | pixel_ptr = y_ptr; |
791 | 5.26k | CHECK_PIXEL_PTR(0); |
792 | 5.26k | pixel_countdown = s->avctx->width; |
793 | 560k | for (i = 0; i < line_packets; i++) { |
794 | | /* account for the skip bytes */ |
795 | 557k | if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk) |
796 | 697 | break; |
797 | 557k | pixel_skip = bytestream2_get_byte(&g2); |
798 | 557k | pixel_ptr += (pixel_skip*2); /* Pixel is 2 bytes wide */ |
799 | 557k | pixel_countdown -= pixel_skip; |
800 | 557k | byte_run = sign_extend(bytestream2_get_byte(&g2), 8); |
801 | 557k | if (byte_run < 0) { |
802 | 117k | byte_run = -byte_run; |
803 | 117k | pixel = bytestream2_get_le16(&g2); |
804 | 117k | CHECK_PIXEL_PTR(2 * byte_run); |
805 | 5.75M | for (j = 0; j < byte_run; j++, pixel_countdown -= 2) { |
806 | 5.63M | *((signed short*)(&pixels[pixel_ptr])) = pixel; |
807 | 5.63M | pixel_ptr += 2; |
808 | 5.63M | } |
809 | 439k | } else { |
810 | 439k | if (bytestream2_tell(&g2) + 2*byte_run > stream_ptr_after_chunk) |
811 | 1.69k | break; |
812 | 437k | CHECK_PIXEL_PTR(2 * byte_run); |
813 | 2.78M | for (j = 0; j < byte_run; j++, pixel_countdown--) { |
814 | 2.34M | *((signed short*)(&pixels[pixel_ptr])) = bytestream2_get_le16(&g2); |
815 | 2.34M | pixel_ptr += 2; |
816 | 2.34M | } |
817 | 437k | } |
818 | 557k | } |
819 | | |
820 | 4.79k | y_ptr += s->frame->linesize[0]; |
821 | 4.79k | } |
822 | 6.58k | } |
823 | 2.76k | break; |
824 | | |
825 | 2.76k | case FLI_LC: |
826 | 439 | av_log(avctx, AV_LOG_ERROR, "Unexpected FLI_LC chunk in non-palettized FLC\n"); |
827 | 439 | bytestream2_skip(&g2, chunk_size - 6); |
828 | 439 | break; |
829 | | |
830 | 229 | case FLI_BLACK: |
831 | | /* set the whole frame to 0x0000 which is black in both 15Bpp and 16Bpp modes. */ |
832 | 1.54M | for (int y = 0; y < s->avctx->height; y++) |
833 | 1.54M | memset(pixels + y * s->frame->linesize[0], 0, s->avctx->width * 2); |
834 | 229 | break; |
835 | | |
836 | 812 | case FLI_BRUN: |
837 | 812 | y_ptr = 0; |
838 | 3.18M | for (lines = 0; lines < s->avctx->height; lines++) { |
839 | 3.18M | pixel_ptr = y_ptr; |
840 | | /* disregard the line packets; instead, iterate through all |
841 | | * pixels on a row */ |
842 | 3.18M | bytestream2_skip(&g2, 1); |
843 | 3.18M | pixel_countdown = (s->avctx->width * 2); |
844 | | |
845 | 3.84M | while (pixel_countdown > 0) { |
846 | 3.82M | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
847 | 3.16M | break; |
848 | 657k | byte_run = sign_extend(bytestream2_get_byte(&g2), 8); |
849 | 657k | if (byte_run > 0) { |
850 | 254k | palette_idx1 = bytestream2_get_byte(&g2); |
851 | 254k | CHECK_PIXEL_PTR(byte_run); |
852 | 8.59M | for (j = 0; j < byte_run; j++) { |
853 | 8.33M | pixels[pixel_ptr++] = palette_idx1; |
854 | 8.33M | pixel_countdown--; |
855 | 8.33M | if (pixel_countdown < 0) |
856 | 633k | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) (linea%d)\n", |
857 | 633k | pixel_countdown, lines); |
858 | 8.33M | } |
859 | 402k | } else { /* copy bytes if byte_run < 0 */ |
860 | 402k | byte_run = -byte_run; |
861 | 402k | if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk) |
862 | 1.18k | break; |
863 | 401k | CHECK_PIXEL_PTR(byte_run); |
864 | 2.99M | for (j = 0; j < byte_run; j++) { |
865 | 2.59M | palette_idx1 = bytestream2_get_byte(&g2); |
866 | 2.59M | pixels[pixel_ptr++] = palette_idx1; |
867 | 2.59M | pixel_countdown--; |
868 | 2.59M | if (pixel_countdown < 0) |
869 | 223k | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n", |
870 | 223k | pixel_countdown, lines); |
871 | 2.59M | } |
872 | 401k | } |
873 | 657k | } |
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 | 3.18M | y_ptr += s->frame->linesize[0]; |
889 | 3.18M | } |
890 | 382 | break; |
891 | | |
892 | 951 | case FLI_DTA_BRUN: |
893 | 951 | y_ptr = 0; |
894 | 2.96M | for (lines = 0; lines < s->avctx->height; lines++) { |
895 | 2.95M | pixel_ptr = y_ptr; |
896 | | /* disregard the line packets; instead, iterate through all |
897 | | * pixels on a row */ |
898 | 2.95M | bytestream2_skip(&g2, 1); |
899 | 2.95M | 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.93M | break; |
904 | 612k | byte_run = sign_extend(bytestream2_get_byte(&g2), 8); |
905 | 612k | if (byte_run > 0) { |
906 | 207k | pixel = bytestream2_get_le16(&g2); |
907 | 207k | CHECK_PIXEL_PTR(2 * byte_run); |
908 | 4.68M | for (j = 0; j < byte_run; j++) { |
909 | 4.48M | *((signed short*)(&pixels[pixel_ptr])) = pixel; |
910 | 4.48M | pixel_ptr += 2; |
911 | 4.48M | pixel_countdown--; |
912 | 4.48M | if (pixel_countdown < 0) |
913 | 646k | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n", |
914 | 646k | pixel_countdown); |
915 | 4.48M | } |
916 | 404k | } else { /* copy pixels if byte_run < 0 */ |
917 | 404k | byte_run = -byte_run; |
918 | 404k | if (bytestream2_tell(&g2) + 2 * byte_run > stream_ptr_after_chunk) |
919 | 1.07k | break; |
920 | 403k | CHECK_PIXEL_PTR(2 * byte_run); |
921 | 2.92M | for (j = 0; j < byte_run; j++) { |
922 | 2.52M | *((signed short*)(&pixels[pixel_ptr])) = bytestream2_get_le16(&g2); |
923 | 2.52M | pixel_ptr += 2; |
924 | 2.52M | pixel_countdown--; |
925 | 2.52M | if (pixel_countdown < 0) |
926 | 399k | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n", |
927 | 399k | pixel_countdown); |
928 | 2.52M | } |
929 | 403k | } |
930 | 612k | } |
931 | | |
932 | 2.95M | y_ptr += s->frame->linesize[0]; |
933 | 2.95M | } |
934 | 504 | break; |
935 | | |
936 | 1.06k | case FLI_COPY: |
937 | 1.33k | case FLI_DTA_COPY: |
938 | | /* copy the chunk (uncompressed frame) */ |
939 | 1.33k | if (chunk_size - 6 > (unsigned int)(FFALIGN(s->avctx->width, 2) * s->avctx->height)*2) { |
940 | 645 | av_log(avctx, AV_LOG_ERROR, "In chunk FLI_COPY : source data (%d bytes) " \ |
941 | 645 | "bigger than image, skipping chunk\n", chunk_size - 6); |
942 | 645 | bytestream2_skip(&g2, chunk_size - 6); |
943 | 691 | } else { |
944 | | |
945 | 691 | if (bytestream2_get_bytes_left(&g2) < 2 * s->avctx->width * s->avctx->height ) |
946 | 405 | return AVERROR_INVALIDDATA; |
947 | 66.0k | for (y_ptr = 0; check_pixel_ptr(y_ptr, 2*s->avctx->width, pixel_limit, direction) == 0; |
948 | 65.7k | y_ptr += s->frame->linesize[0]) { |
949 | | |
950 | 65.7k | pixel_countdown = s->avctx->width; |
951 | 65.7k | pixel_ptr = 0; |
952 | 401k | while (pixel_countdown > 0) { |
953 | 335k | *((signed short*)(&pixels[y_ptr + pixel_ptr])) = bytestream2_get_le16(&g2); |
954 | 335k | pixel_ptr += 2; |
955 | 335k | pixel_countdown--; |
956 | 335k | } |
957 | 65.7k | if (s->avctx->width & 1) |
958 | 65.5k | bytestream2_skip(&g2, 2); |
959 | 65.7k | } |
960 | 286 | } |
961 | 931 | break; |
962 | | |
963 | 931 | case FLI_MINI: |
964 | | /* some sort of a thumbnail? disregard this chunk... */ |
965 | 419 | bytestream2_skip(&g2, chunk_size - 6); |
966 | 419 | break; |
967 | | |
968 | 5.31k | default: |
969 | 5.31k | av_log(avctx, AV_LOG_ERROR, "Unrecognized chunk type: %d\n", chunk_type); |
970 | 5.31k | break; |
971 | 14.2k | } |
972 | | |
973 | 11.7k | if (stream_ptr_after_chunk - bytestream2_tell(&g2) >= 0) { |
974 | 10.5k | bytestream2_skip(&g2, stream_ptr_after_chunk - bytestream2_tell(&g2)); |
975 | 10.5k | } else { |
976 | 1.19k | av_log(avctx, AV_LOG_ERROR, "Chunk overread\n"); |
977 | 1.19k | break; |
978 | 1.19k | } |
979 | | |
980 | 10.5k | frame_size -= chunk_size; |
981 | 10.5k | num_chunks--; |
982 | 10.5k | } |
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 | 71.2k | if ((bytestream2_get_bytes_left(&g2) != 0) && (bytestream2_get_bytes_left(&g2) != 1)) |
987 | 8.43k | av_log(avctx, AV_LOG_ERROR, "Processed FLI chunk where chunk size = %d " \ |
988 | 8.43k | "and final chunk ptr = %d\n", buf_size, bytestream2_tell(&g2)); |
989 | | |
990 | 71.2k | if ((ret = av_frame_ref(rframe, s->frame)) < 0) |
991 | 0 | return ret; |
992 | | |
993 | 71.2k | *got_frame = 1; |
994 | | |
995 | 71.2k | return buf_size; |
996 | 71.2k | } |
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 | 13.2k | { |
1002 | 13.2k | FlicDecodeContext *s = avctx->priv_data; |
1003 | | |
1004 | 13.2k | GetByteContext g2; |
1005 | 13.2k | ptrdiff_t pixel_ptr; |
1006 | 13.2k | unsigned char palette_idx1; |
1007 | | |
1008 | 13.2k | unsigned int frame_size; |
1009 | 13.2k | int num_chunks; |
1010 | | |
1011 | 13.2k | unsigned int chunk_size; |
1012 | 13.2k | int chunk_type; |
1013 | | |
1014 | 13.2k | int i, j, ret, direction; |
1015 | | |
1016 | 13.2k | int lines; |
1017 | 13.2k | int compressed_lines; |
1018 | 13.2k | int line_packets; |
1019 | 13.2k | ptrdiff_t y_ptr; |
1020 | 13.2k | int byte_run; |
1021 | 13.2k | int pixel_skip; |
1022 | 13.2k | int pixel_countdown; |
1023 | 13.2k | unsigned char *pixels; |
1024 | 13.2k | int pixel; |
1025 | 13.2k | ptrdiff_t pixel_limit; |
1026 | | |
1027 | 13.2k | bytestream2_init(&g2, buf, buf_size); |
1028 | | |
1029 | 13.2k | if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0) |
1030 | 214 | return ret; |
1031 | | |
1032 | 13.0k | direction = s->frame->linesize[0] > 0; |
1033 | 13.0k | pixels = s->frame->data[0]; |
1034 | 13.0k | pixel_limit = s->avctx->height * s->frame->linesize[0]; |
1035 | | |
1036 | 13.0k | frame_size = bytestream2_get_le32(&g2); |
1037 | 13.0k | bytestream2_skip(&g2, 2); /* skip the magic number */ |
1038 | 13.0k | num_chunks = bytestream2_get_le16(&g2); |
1039 | 13.0k | bytestream2_skip(&g2, 8); /* skip padding */ |
1040 | 13.0k | if (frame_size > buf_size) |
1041 | 11.6k | frame_size = buf_size; |
1042 | | |
1043 | 13.0k | if (frame_size < 16) |
1044 | 2.29k | return AVERROR_INVALIDDATA; |
1045 | 10.7k | frame_size -= 16; |
1046 | | |
1047 | | /* iterate through the chunks */ |
1048 | 18.0k | while ((frame_size > 0) && (num_chunks > 0) && |
1049 | 11.5k | bytestream2_get_bytes_left(&g2) >= 4) { |
1050 | 10.7k | int stream_ptr_after_chunk; |
1051 | 10.7k | chunk_size = bytestream2_get_le32(&g2); |
1052 | 10.7k | if (chunk_size > frame_size) { |
1053 | 7.62k | av_log(avctx, AV_LOG_WARNING, |
1054 | 7.62k | "Invalid chunk_size = %u > frame_size = %u\n", chunk_size, frame_size); |
1055 | 7.62k | chunk_size = frame_size; |
1056 | 7.62k | } |
1057 | 10.7k | stream_ptr_after_chunk = bytestream2_tell(&g2) - 4 + chunk_size; |
1058 | | |
1059 | 10.7k | chunk_type = bytestream2_get_le16(&g2); |
1060 | | |
1061 | | |
1062 | 10.7k | switch (chunk_type) { |
1063 | 666 | case FLI_256_COLOR: |
1064 | 875 | 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 | 875 | ff_dlog(avctx, |
1069 | 875 | "Unexpected Palette chunk %d in non-palettized FLC\n", |
1070 | 875 | chunk_type); |
1071 | 875 | bytestream2_skip(&g2, chunk_size - 6); |
1072 | 875 | break; |
1073 | | |
1074 | 2.13k | case FLI_DELTA: |
1075 | 2.35k | case FLI_DTA_LC: |
1076 | 2.35k | y_ptr = 0; |
1077 | 2.35k | compressed_lines = bytestream2_get_le16(&g2); |
1078 | 7.66k | while (compressed_lines > 0) { |
1079 | 7.06k | if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk) |
1080 | 732 | break; |
1081 | 6.33k | CHECK_Y_PTR() |
1082 | 6.08k | line_packets = sign_extend(bytestream2_get_le16(&g2), 16); |
1083 | 6.08k | if (line_packets < 0) { |
1084 | 1.04k | line_packets = -line_packets; |
1085 | 1.04k | if (line_packets > s->avctx->height) |
1086 | 342 | return AVERROR_INVALIDDATA; |
1087 | 700 | y_ptr += line_packets * s->frame->linesize[0]; |
1088 | 5.04k | } else { |
1089 | 5.04k | compressed_lines--; |
1090 | 5.04k | pixel_ptr = y_ptr; |
1091 | 5.04k | CHECK_PIXEL_PTR(0); |
1092 | 5.04k | pixel_countdown = s->avctx->width; |
1093 | 772k | for (i = 0; i < line_packets; i++) { |
1094 | | /* account for the skip bytes */ |
1095 | 770k | if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk) |
1096 | 625 | break; |
1097 | 769k | pixel_skip = bytestream2_get_byte(&g2); |
1098 | 769k | pixel_ptr += (pixel_skip*3); /* Pixel is 3 bytes wide */ |
1099 | 769k | pixel_countdown -= pixel_skip; |
1100 | 769k | byte_run = sign_extend(bytestream2_get_byte(&g2), 8); |
1101 | 769k | if (byte_run < 0) { |
1102 | 148k | byte_run = -byte_run; |
1103 | 148k | pixel = bytestream2_get_le24(&g2); |
1104 | 148k | CHECK_PIXEL_PTR(3 * byte_run); |
1105 | 6.56M | for (j = 0; j < byte_run; j++, pixel_countdown -= 1) { |
1106 | 6.41M | AV_WL24(&pixels[pixel_ptr], pixel); |
1107 | 6.41M | pixel_ptr += 3; |
1108 | 6.41M | } |
1109 | 621k | } else { |
1110 | 621k | if (bytestream2_tell(&g2) + 2*byte_run > stream_ptr_after_chunk) |
1111 | 1.56k | break; |
1112 | 619k | CHECK_PIXEL_PTR(3 * byte_run); |
1113 | 3.05M | for (j = 0; j < byte_run; j++, pixel_countdown--) { |
1114 | 2.43M | pixel = bytestream2_get_le24(&g2); |
1115 | 2.43M | AV_WL24(&pixels[pixel_ptr], pixel); |
1116 | 2.43M | pixel_ptr += 3; |
1117 | 2.43M | } |
1118 | 619k | } |
1119 | 769k | } |
1120 | | |
1121 | 4.60k | y_ptr += s->frame->linesize[0]; |
1122 | 4.60k | } |
1123 | 6.08k | } |
1124 | 1.32k | break; |
1125 | | |
1126 | 1.56k | case FLI_LC: |
1127 | 1.56k | av_log(avctx, AV_LOG_ERROR, "Unexpected FLI_LC chunk in non-palettized FLC\n"); |
1128 | 1.56k | bytestream2_skip(&g2, chunk_size - 6); |
1129 | 1.56k | break; |
1130 | | |
1131 | 284 | case FLI_BLACK: |
1132 | | /* set the whole frame to 0x00 which is black for 24 bit mode. */ |
1133 | 2.49M | for (int y = 0; y < s->avctx->height; y++) |
1134 | 2.49M | memset(pixels + y * s->frame->linesize[0], 0, s->avctx->width * 3); |
1135 | 284 | break; |
1136 | | |
1137 | 1.23k | case FLI_BRUN: |
1138 | 1.23k | y_ptr = 0; |
1139 | 3.87M | for (lines = 0; lines < s->avctx->height; lines++) { |
1140 | 3.87M | pixel_ptr = y_ptr; |
1141 | | /* disregard the line packets; instead, iterate through all |
1142 | | * pixels on a row */ |
1143 | 3.87M | bytestream2_skip(&g2, 1); |
1144 | 3.87M | pixel_countdown = (s->avctx->width * 3); |
1145 | | |
1146 | 4.76M | while (pixel_countdown > 0) { |
1147 | 4.75M | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
1148 | 3.87M | break; |
1149 | 887k | byte_run = sign_extend(bytestream2_get_byte(&g2), 8); |
1150 | 887k | if (byte_run > 0) { |
1151 | 269k | palette_idx1 = bytestream2_get_byte(&g2); |
1152 | 269k | CHECK_PIXEL_PTR(byte_run); |
1153 | 8.54M | for (j = 0; j < byte_run; j++) { |
1154 | 8.28M | pixels[pixel_ptr++] = palette_idx1; |
1155 | 8.28M | pixel_countdown--; |
1156 | 8.28M | if (pixel_countdown < 0) |
1157 | 88.7k | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) (linea%d)\n", |
1158 | 88.7k | pixel_countdown, lines); |
1159 | 8.28M | } |
1160 | 618k | } else { /* copy bytes if byte_run < 0 */ |
1161 | 618k | byte_run = -byte_run; |
1162 | 618k | if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk) |
1163 | 1.50k | break; |
1164 | 616k | CHECK_PIXEL_PTR(byte_run); |
1165 | 6.55M | for (j = 0; j < byte_run; j++) { |
1166 | 5.93M | palette_idx1 = bytestream2_get_byte(&g2); |
1167 | 5.93M | pixels[pixel_ptr++] = palette_idx1; |
1168 | 5.93M | pixel_countdown--; |
1169 | 5.93M | if (pixel_countdown < 0) |
1170 | 14.9k | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n", |
1171 | 14.9k | pixel_countdown, lines); |
1172 | 5.93M | } |
1173 | 616k | } |
1174 | 887k | } |
1175 | | |
1176 | 3.87M | y_ptr += s->frame->linesize[0]; |
1177 | 3.87M | } |
1178 | 831 | break; |
1179 | | |
1180 | 923 | case FLI_DTA_BRUN: |
1181 | 923 | y_ptr = 0; |
1182 | 5.32M | for (lines = 0; lines < s->avctx->height; lines++) { |
1183 | 5.32M | pixel_ptr = y_ptr; |
1184 | | /* disregard the line packets; instead, iterate through all |
1185 | | * pixels on a row */ |
1186 | 5.32M | bytestream2_skip(&g2, 1); |
1187 | 5.32M | pixel_countdown = s->avctx->width; /* Width is in pixels, not bytes */ |
1188 | | |
1189 | 5.51M | while (pixel_countdown > 0) { |
1190 | 5.51M | if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) |
1191 | 5.32M | break; |
1192 | 197k | byte_run = sign_extend(bytestream2_get_byte(&g2), 8); |
1193 | 197k | if (byte_run > 0) { |
1194 | 51.7k | pixel = bytestream2_get_le24(&g2); |
1195 | 51.7k | CHECK_PIXEL_PTR(3 * byte_run); |
1196 | 2.44M | for (j = 0; j < byte_run; j++) { |
1197 | 2.39M | AV_WL24(pixels + pixel_ptr, pixel); |
1198 | 2.39M | pixel_ptr += 3; |
1199 | 2.39M | pixel_countdown--; |
1200 | 2.39M | if (pixel_countdown < 0) |
1201 | 34.8k | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n", |
1202 | 34.8k | pixel_countdown); |
1203 | 2.39M | } |
1204 | 145k | } else { /* copy pixels if byte_run < 0 */ |
1205 | 145k | byte_run = -byte_run; |
1206 | 145k | if (bytestream2_tell(&g2) + 3 * byte_run > stream_ptr_after_chunk) |
1207 | 1.21k | break; |
1208 | 144k | CHECK_PIXEL_PTR(3 * byte_run); |
1209 | 1.14M | for (j = 0; j < byte_run; j++) { |
1210 | 996k | pixel = bytestream2_get_le24(&g2); |
1211 | 996k | AV_WL24(pixels + pixel_ptr, pixel); |
1212 | 996k | pixel_ptr += 3; |
1213 | 996k | pixel_countdown--; |
1214 | 996k | if (pixel_countdown < 0) |
1215 | 11.1k | av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n", |
1216 | 11.1k | pixel_countdown); |
1217 | 996k | } |
1218 | 144k | } |
1219 | 197k | } |
1220 | | |
1221 | 5.32M | y_ptr += s->frame->linesize[0]; |
1222 | 5.32M | } |
1223 | 490 | break; |
1224 | | |
1225 | 525 | case FLI_COPY: |
1226 | 753 | case FLI_DTA_COPY: |
1227 | | /* copy the chunk (uncompressed frame) */ |
1228 | 753 | if (chunk_size - 6 > (unsigned int)(FFALIGN(s->avctx->width, 2) * s->avctx->height)*3) { |
1229 | 463 | av_log(avctx, AV_LOG_ERROR, "In chunk FLI_COPY : source data (%d bytes) " \ |
1230 | 463 | "bigger than image, skipping chunk\n", chunk_size - 6); |
1231 | 463 | bytestream2_skip(&g2, chunk_size - 6); |
1232 | 463 | } else { |
1233 | 2.94M | for (y_ptr = 0; check_pixel_ptr(y_ptr, 3*s->avctx->width, pixel_limit, direction) == 0; |
1234 | 2.94M | y_ptr += s->frame->linesize[0]) { |
1235 | | |
1236 | 2.94M | bytestream2_get_buffer(&g2, pixels + y_ptr, 3*s->avctx->width); |
1237 | 2.94M | if (s->avctx->width & 1) |
1238 | 1.95M | bytestream2_skip(&g2, 3); |
1239 | 2.94M | } |
1240 | 290 | } |
1241 | 753 | break; |
1242 | | |
1243 | 475 | case FLI_MINI: |
1244 | | /* some sort of a thumbnail? disregard this chunk... */ |
1245 | 475 | bytestream2_skip(&g2, chunk_size - 6); |
1246 | 475 | break; |
1247 | | |
1248 | 2.25k | default: |
1249 | 2.25k | av_log(avctx, AV_LOG_ERROR, "Unrecognized chunk type: %d\n", chunk_type); |
1250 | 2.25k | break; |
1251 | 10.7k | } |
1252 | | |
1253 | 8.85k | if (stream_ptr_after_chunk - bytestream2_tell(&g2) >= 0) { |
1254 | 7.26k | bytestream2_skip(&g2, stream_ptr_after_chunk - bytestream2_tell(&g2)); |
1255 | 7.26k | } else { |
1256 | 1.59k | av_log(avctx, AV_LOG_ERROR, "Chunk overread\n"); |
1257 | 1.59k | break; |
1258 | 1.59k | } |
1259 | | |
1260 | 7.26k | frame_size -= chunk_size; |
1261 | 7.26k | num_chunks--; |
1262 | 7.26k | } |
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 | 8.88k | if ((bytestream2_get_bytes_left(&g2) != 0) && (bytestream2_get_bytes_left(&g2) != 1)) |
1267 | 939 | av_log(avctx, AV_LOG_ERROR, "Processed FLI chunk where chunk size = %d " \ |
1268 | 939 | "and final chunk ptr = %d\n", buf_size, bytestream2_tell(&g2)); |
1269 | | |
1270 | 8.88k | if ((ret = av_frame_ref(rframe, s->frame)) < 0) |
1271 | 0 | return ret; |
1272 | | |
1273 | 8.88k | *got_frame = 1; |
1274 | | |
1275 | 8.88k | return buf_size; |
1276 | 8.88k | } |
1277 | | |
1278 | | static int flic_decode_frame(AVCodecContext *avctx, AVFrame *frame, |
1279 | | int *got_frame, AVPacket *avpkt) |
1280 | 133k | { |
1281 | 133k | const uint8_t *buf = avpkt->data; |
1282 | 133k | int buf_size = avpkt->size; |
1283 | 133k | if (avctx->pix_fmt == AV_PIX_FMT_MONOBLACK) { |
1284 | 8.40k | return flic_decode_frame_1BPP(avctx, frame, got_frame, |
1285 | 8.40k | buf, buf_size); |
1286 | 125k | } else if (avctx->pix_fmt == AV_PIX_FMT_PAL8) { |
1287 | 33.5k | return flic_decode_frame_8BPP(avctx, frame, got_frame, |
1288 | 33.5k | buf, buf_size); |
1289 | 91.5k | } else if ((avctx->pix_fmt == AV_PIX_FMT_RGB555) || |
1290 | 87.7k | (avctx->pix_fmt == AV_PIX_FMT_RGB565)) { |
1291 | 78.2k | return flic_decode_frame_15_16BPP(avctx, frame, got_frame, |
1292 | 78.2k | buf, buf_size); |
1293 | 78.2k | } else if (avctx->pix_fmt == AV_PIX_FMT_BGR24) { |
1294 | 13.2k | return flic_decode_frame_24BPP(avctx, frame, got_frame, |
1295 | 13.2k | buf, buf_size); |
1296 | 13.2k | } |
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 | 133k | } |
1305 | | |
1306 | | |
1307 | | static av_cold int flic_decode_end(AVCodecContext *avctx) |
1308 | 2.69k | { |
1309 | 2.69k | FlicDecodeContext *s = avctx->priv_data; |
1310 | | |
1311 | 2.69k | av_frame_free(&s->frame); |
1312 | | |
1313 | 2.69k | return 0; |
1314 | 2.69k | } |
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 | | }; |