ffmpeg / libavcodec / flicvideo.c @ d36beb3f
History | View | Annotate | Download (28.3 KB)
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 and maybe one day RGB24
|
31 |
* colorspace data, depending on the FLC. To use this decoder, be
|
32 |
* sure that your demuxer sends the FLI file header to the decoder via
|
33 |
* the extradata chunk in AVCodecContext. The chunk should be 128 bytes
|
34 |
* large. The only exception is for FLI files from the game "Magic Carpet",
|
35 |
* in which the header is only 12 bytes.
|
36 |
*/
|
37 |
|
38 |
#include <stdio.h> |
39 |
#include <stdlib.h> |
40 |
#include <string.h> |
41 |
|
42 |
#include "libavutil/intreadwrite.h" |
43 |
#include "avcodec.h" |
44 |
|
45 |
#define FLI_256_COLOR 4 |
46 |
#define FLI_DELTA 7 |
47 |
#define FLI_COLOR 11 |
48 |
#define FLI_LC 12 |
49 |
#define FLI_BLACK 13 |
50 |
#define FLI_BRUN 15 |
51 |
#define FLI_COPY 16 |
52 |
#define FLI_MINI 18 |
53 |
#define FLI_DTA_BRUN 25 |
54 |
#define FLI_DTA_COPY 26 |
55 |
#define FLI_DTA_LC 27 |
56 |
|
57 |
#define FLI_TYPE_CODE (0xAF11) |
58 |
#define FLC_FLX_TYPE_CODE (0xAF12) |
59 |
#define FLC_DTA_TYPE_CODE (0xAF44) /* Marks an "Extended FLC" comes from Dave's Targa Animator (DTA) */ |
60 |
#define FLC_MAGIC_CARPET_SYNTHETIC_TYPE_CODE (0xAF13) |
61 |
|
62 |
#define CHECK_PIXEL_PTR(n) \
|
63 |
if (pixel_ptr + n > pixel_limit) { \
|
64 |
av_log (s->avctx, AV_LOG_INFO, "Problem: pixel_ptr >= pixel_limit (%d >= %d)\n", \
|
65 |
pixel_ptr + n, pixel_limit); \ |
66 |
return -1; \ |
67 |
} \ |
68 |
|
69 |
typedef struct FlicDecodeContext { |
70 |
AVCodecContext *avctx; |
71 |
AVFrame frame; |
72 |
|
73 |
unsigned int palette[256]; |
74 |
int new_palette;
|
75 |
int fli_type; /* either 0xAF11 or 0xAF12, affects palette resolution */ |
76 |
} FlicDecodeContext; |
77 |
|
78 |
static av_cold int flic_decode_init(AVCodecContext *avctx) |
79 |
{ |
80 |
FlicDecodeContext *s = avctx->priv_data; |
81 |
unsigned char *fli_header = (unsigned char *)avctx->extradata; |
82 |
int depth;
|
83 |
|
84 |
s->avctx = avctx; |
85 |
|
86 |
s->fli_type = AV_RL16(&fli_header[4]); /* Might be overridden if a Magic Carpet FLC */ |
87 |
|
88 |
depth = 0;
|
89 |
if (s->avctx->extradata_size == 12) { |
90 |
/* special case for magic carpet FLIs */
|
91 |
s->fli_type = FLC_MAGIC_CARPET_SYNTHETIC_TYPE_CODE; |
92 |
depth = 8;
|
93 |
} else if (s->avctx->extradata_size != 128) { |
94 |
av_log(avctx, AV_LOG_ERROR, "Expected extradata of 12 or 128 bytes\n");
|
95 |
return -1; |
96 |
} else {
|
97 |
depth = AV_RL16(&fli_header[12]);
|
98 |
} |
99 |
|
100 |
if (depth == 0) { |
101 |
depth = 8; /* Some FLC generators set depth to zero, when they mean 8Bpp. Fix up here */ |
102 |
} |
103 |
|
104 |
if ((s->fli_type == FLC_FLX_TYPE_CODE) && (depth == 16)) { |
105 |
depth = 15; /* Original Autodesk FLX's say the depth is 16Bpp when it is really 15Bpp */ |
106 |
} |
107 |
|
108 |
switch (depth) {
|
109 |
case 8 : avctx->pix_fmt = PIX_FMT_PAL8; break; |
110 |
case 15 : avctx->pix_fmt = PIX_FMT_RGB555; break; |
111 |
case 16 : avctx->pix_fmt = PIX_FMT_RGB565; break; |
112 |
case 24 : avctx->pix_fmt = PIX_FMT_BGR24; /* Supposedly BGR, but havent any files to test with */ |
113 |
av_log(avctx, AV_LOG_ERROR, "24Bpp FLC/FLX is unsupported due to no test files.\n");
|
114 |
return -1; |
115 |
break;
|
116 |
default :
|
117 |
av_log(avctx, AV_LOG_ERROR, "Unknown FLC/FLX depth of %d Bpp is unsupported.\n",depth);
|
118 |
return -1; |
119 |
} |
120 |
|
121 |
s->frame.data[0] = NULL; |
122 |
s->new_palette = 0;
|
123 |
|
124 |
return 0; |
125 |
} |
126 |
|
127 |
static int flic_decode_frame_8BPP(AVCodecContext *avctx, |
128 |
void *data, int *data_size, |
129 |
const uint8_t *buf, int buf_size) |
130 |
{ |
131 |
FlicDecodeContext *s = avctx->priv_data; |
132 |
|
133 |
int stream_ptr = 0; |
134 |
int stream_ptr_after_color_chunk;
|
135 |
int pixel_ptr;
|
136 |
int palette_ptr;
|
137 |
unsigned char palette_idx1; |
138 |
unsigned char palette_idx2; |
139 |
|
140 |
unsigned int frame_size; |
141 |
int num_chunks;
|
142 |
|
143 |
unsigned int chunk_size; |
144 |
int chunk_type;
|
145 |
|
146 |
int i, j;
|
147 |
|
148 |
int color_packets;
|
149 |
int color_changes;
|
150 |
int color_shift;
|
151 |
unsigned char r, g, b; |
152 |
|
153 |
int lines;
|
154 |
int compressed_lines;
|
155 |
int starting_line;
|
156 |
signed short line_packets; |
157 |
int y_ptr;
|
158 |
int byte_run;
|
159 |
int pixel_skip;
|
160 |
int pixel_countdown;
|
161 |
unsigned char *pixels; |
162 |
unsigned int pixel_limit; |
163 |
|
164 |
s->frame.reference = 1;
|
165 |
s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE; |
166 |
if (avctx->reget_buffer(avctx, &s->frame) < 0) { |
167 |
av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
|
168 |
return -1; |
169 |
} |
170 |
|
171 |
pixels = s->frame.data[0];
|
172 |
pixel_limit = s->avctx->height * s->frame.linesize[0];
|
173 |
|
174 |
frame_size = AV_RL32(&buf[stream_ptr]); |
175 |
stream_ptr += 6; /* skip the magic number */ |
176 |
num_chunks = AV_RL16(&buf[stream_ptr]); |
177 |
stream_ptr += 10; /* skip padding */ |
178 |
|
179 |
frame_size -= 16;
|
180 |
|
181 |
/* iterate through the chunks */
|
182 |
while ((frame_size > 0) && (num_chunks > 0)) { |
183 |
chunk_size = AV_RL32(&buf[stream_ptr]); |
184 |
stream_ptr += 4;
|
185 |
chunk_type = AV_RL16(&buf[stream_ptr]); |
186 |
stream_ptr += 2;
|
187 |
|
188 |
switch (chunk_type) {
|
189 |
case FLI_256_COLOR:
|
190 |
case FLI_COLOR:
|
191 |
stream_ptr_after_color_chunk = stream_ptr + chunk_size - 6;
|
192 |
|
193 |
/* check special case: If this file is from the Magic Carpet
|
194 |
* game and uses 6-bit colors even though it reports 256-color
|
195 |
* chunks in a 0xAF12-type file (fli_type is set to 0xAF13 during
|
196 |
* initialization) */
|
197 |
if ((chunk_type == FLI_256_COLOR) && (s->fli_type != FLC_MAGIC_CARPET_SYNTHETIC_TYPE_CODE))
|
198 |
color_shift = 0;
|
199 |
else
|
200 |
color_shift = 2;
|
201 |
/* set up the palette */
|
202 |
color_packets = AV_RL16(&buf[stream_ptr]); |
203 |
stream_ptr += 2;
|
204 |
palette_ptr = 0;
|
205 |
for (i = 0; i < color_packets; i++) { |
206 |
/* first byte is how many colors to skip */
|
207 |
palette_ptr += buf[stream_ptr++]; |
208 |
|
209 |
/* next byte indicates how many entries to change */
|
210 |
color_changes = buf[stream_ptr++]; |
211 |
|
212 |
/* if there are 0 color changes, there are actually 256 */
|
213 |
if (color_changes == 0) |
214 |
color_changes = 256;
|
215 |
|
216 |
for (j = 0; j < color_changes; j++) { |
217 |
unsigned int entry; |
218 |
|
219 |
/* wrap around, for good measure */
|
220 |
if ((unsigned)palette_ptr >= 256) |
221 |
palette_ptr = 0;
|
222 |
|
223 |
r = buf[stream_ptr++] << color_shift; |
224 |
g = buf[stream_ptr++] << color_shift; |
225 |
b = buf[stream_ptr++] << color_shift; |
226 |
entry = (r << 16) | (g << 8) | b; |
227 |
if (s->palette[palette_ptr] != entry)
|
228 |
s->new_palette = 1;
|
229 |
s->palette[palette_ptr++] = entry; |
230 |
} |
231 |
} |
232 |
|
233 |
/* color chunks sometimes have weird 16-bit alignment issues;
|
234 |
* therefore, take the hardline approach and set the stream_ptr
|
235 |
* to the value calculated w.r.t. the size specified by the color
|
236 |
* chunk header */
|
237 |
stream_ptr = stream_ptr_after_color_chunk; |
238 |
|
239 |
break;
|
240 |
|
241 |
case FLI_DELTA:
|
242 |
y_ptr = 0;
|
243 |
compressed_lines = AV_RL16(&buf[stream_ptr]); |
244 |
stream_ptr += 2;
|
245 |
while (compressed_lines > 0) { |
246 |
line_packets = AV_RL16(&buf[stream_ptr]); |
247 |
stream_ptr += 2;
|
248 |
if ((line_packets & 0xC000) == 0xC000) { |
249 |
// line skip opcode
|
250 |
line_packets = -line_packets; |
251 |
y_ptr += line_packets * s->frame.linesize[0];
|
252 |
} else if ((line_packets & 0xC000) == 0x4000) { |
253 |
av_log(avctx, AV_LOG_ERROR, "Undefined opcode (%x) in DELTA_FLI\n", line_packets);
|
254 |
} else if ((line_packets & 0xC000) == 0x8000) { |
255 |
// "last byte" opcode
|
256 |
pixel_ptr= y_ptr + s->frame.linesize[0] - 1; |
257 |
CHECK_PIXEL_PTR(0);
|
258 |
pixels[pixel_ptr] = line_packets & 0xff;
|
259 |
} else {
|
260 |
compressed_lines--; |
261 |
pixel_ptr = y_ptr; |
262 |
CHECK_PIXEL_PTR(0);
|
263 |
pixel_countdown = s->avctx->width; |
264 |
for (i = 0; i < line_packets; i++) { |
265 |
/* account for the skip bytes */
|
266 |
pixel_skip = buf[stream_ptr++]; |
267 |
pixel_ptr += pixel_skip; |
268 |
pixel_countdown -= pixel_skip; |
269 |
byte_run = (signed char)(buf[stream_ptr++]); |
270 |
if (byte_run < 0) { |
271 |
byte_run = -byte_run; |
272 |
palette_idx1 = buf[stream_ptr++]; |
273 |
palette_idx2 = buf[stream_ptr++]; |
274 |
CHECK_PIXEL_PTR(byte_run * 2);
|
275 |
for (j = 0; j < byte_run; j++, pixel_countdown -= 2) { |
276 |
pixels[pixel_ptr++] = palette_idx1; |
277 |
pixels[pixel_ptr++] = palette_idx2; |
278 |
} |
279 |
} else {
|
280 |
CHECK_PIXEL_PTR(byte_run * 2);
|
281 |
for (j = 0; j < byte_run * 2; j++, pixel_countdown--) { |
282 |
palette_idx1 = buf[stream_ptr++]; |
283 |
pixels[pixel_ptr++] = palette_idx1; |
284 |
} |
285 |
} |
286 |
} |
287 |
|
288 |
y_ptr += s->frame.linesize[0];
|
289 |
} |
290 |
} |
291 |
break;
|
292 |
|
293 |
case FLI_LC:
|
294 |
/* line compressed */
|
295 |
starting_line = AV_RL16(&buf[stream_ptr]); |
296 |
stream_ptr += 2;
|
297 |
y_ptr = 0;
|
298 |
y_ptr += starting_line * s->frame.linesize[0];
|
299 |
|
300 |
compressed_lines = AV_RL16(&buf[stream_ptr]); |
301 |
stream_ptr += 2;
|
302 |
while (compressed_lines > 0) { |
303 |
pixel_ptr = y_ptr; |
304 |
CHECK_PIXEL_PTR(0);
|
305 |
pixel_countdown = s->avctx->width; |
306 |
line_packets = buf[stream_ptr++]; |
307 |
if (line_packets > 0) { |
308 |
for (i = 0; i < line_packets; i++) { |
309 |
/* account for the skip bytes */
|
310 |
pixel_skip = buf[stream_ptr++]; |
311 |
pixel_ptr += pixel_skip; |
312 |
pixel_countdown -= pixel_skip; |
313 |
byte_run = (signed char)(buf[stream_ptr++]); |
314 |
if (byte_run > 0) { |
315 |
CHECK_PIXEL_PTR(byte_run); |
316 |
for (j = 0; j < byte_run; j++, pixel_countdown--) { |
317 |
palette_idx1 = buf[stream_ptr++]; |
318 |
pixels[pixel_ptr++] = palette_idx1; |
319 |
} |
320 |
} else if (byte_run < 0) { |
321 |
byte_run = -byte_run; |
322 |
palette_idx1 = buf[stream_ptr++]; |
323 |
CHECK_PIXEL_PTR(byte_run); |
324 |
for (j = 0; j < byte_run; j++, pixel_countdown--) { |
325 |
pixels[pixel_ptr++] = palette_idx1; |
326 |
} |
327 |
} |
328 |
} |
329 |
} |
330 |
|
331 |
y_ptr += s->frame.linesize[0];
|
332 |
compressed_lines--; |
333 |
} |
334 |
break;
|
335 |
|
336 |
case FLI_BLACK:
|
337 |
/* set the whole frame to color 0 (which is usually black) */
|
338 |
memset(pixels, 0,
|
339 |
s->frame.linesize[0] * s->avctx->height);
|
340 |
break;
|
341 |
|
342 |
case FLI_BRUN:
|
343 |
/* Byte run compression: This chunk type only occurs in the first
|
344 |
* FLI frame and it will update the entire frame. */
|
345 |
y_ptr = 0;
|
346 |
for (lines = 0; lines < s->avctx->height; lines++) { |
347 |
pixel_ptr = y_ptr; |
348 |
/* disregard the line packets; instead, iterate through all
|
349 |
* pixels on a row */
|
350 |
stream_ptr++; |
351 |
pixel_countdown = s->avctx->width; |
352 |
while (pixel_countdown > 0) { |
353 |
byte_run = (signed char)(buf[stream_ptr++]); |
354 |
if (byte_run > 0) { |
355 |
palette_idx1 = buf[stream_ptr++]; |
356 |
CHECK_PIXEL_PTR(byte_run); |
357 |
for (j = 0; j < byte_run; j++) { |
358 |
pixels[pixel_ptr++] = palette_idx1; |
359 |
pixel_countdown--; |
360 |
if (pixel_countdown < 0) |
361 |
av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n",
|
362 |
pixel_countdown, lines); |
363 |
} |
364 |
} else { /* copy bytes if byte_run < 0 */ |
365 |
byte_run = -byte_run; |
366 |
CHECK_PIXEL_PTR(byte_run); |
367 |
for (j = 0; j < byte_run; j++) { |
368 |
palette_idx1 = buf[stream_ptr++]; |
369 |
pixels[pixel_ptr++] = palette_idx1; |
370 |
pixel_countdown--; |
371 |
if (pixel_countdown < 0) |
372 |
av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n",
|
373 |
pixel_countdown, lines); |
374 |
} |
375 |
} |
376 |
} |
377 |
|
378 |
y_ptr += s->frame.linesize[0];
|
379 |
} |
380 |
break;
|
381 |
|
382 |
case FLI_COPY:
|
383 |
/* copy the chunk (uncompressed frame) */
|
384 |
if (chunk_size - 6 > s->avctx->width * s->avctx->height) { |
385 |
av_log(avctx, AV_LOG_ERROR, "In chunk FLI_COPY : source data (%d bytes) " \
|
386 |
"bigger than image, skipping chunk\n", chunk_size - 6); |
387 |
stream_ptr += chunk_size - 6;
|
388 |
} else {
|
389 |
for (y_ptr = 0; y_ptr < s->frame.linesize[0] * s->avctx->height; |
390 |
y_ptr += s->frame.linesize[0]) {
|
391 |
memcpy(&pixels[y_ptr], &buf[stream_ptr], |
392 |
s->avctx->width); |
393 |
stream_ptr += s->avctx->width; |
394 |
} |
395 |
} |
396 |
break;
|
397 |
|
398 |
case FLI_MINI:
|
399 |
/* some sort of a thumbnail? disregard this chunk... */
|
400 |
stream_ptr += chunk_size - 6;
|
401 |
break;
|
402 |
|
403 |
default:
|
404 |
av_log(avctx, AV_LOG_ERROR, "Unrecognized chunk type: %d\n", chunk_type);
|
405 |
break;
|
406 |
} |
407 |
|
408 |
frame_size -= chunk_size; |
409 |
num_chunks--; |
410 |
} |
411 |
|
412 |
/* by the end of the chunk, the stream ptr should equal the frame
|
413 |
* size (minus 1, possibly); if it doesn't, issue a warning */
|
414 |
if ((stream_ptr != buf_size) && (stream_ptr != buf_size - 1)) |
415 |
av_log(avctx, AV_LOG_ERROR, "Processed FLI chunk where chunk size = %d " \
|
416 |
"and final chunk ptr = %d\n", buf_size, stream_ptr);
|
417 |
|
418 |
/* make the palette available on the way out */
|
419 |
memcpy(s->frame.data[1], s->palette, AVPALETTE_SIZE);
|
420 |
if (s->new_palette) {
|
421 |
s->frame.palette_has_changed = 1;
|
422 |
s->new_palette = 0;
|
423 |
} |
424 |
|
425 |
*data_size=sizeof(AVFrame);
|
426 |
*(AVFrame*)data = s->frame; |
427 |
|
428 |
return buf_size;
|
429 |
} |
430 |
|
431 |
static int flic_decode_frame_15_16BPP(AVCodecContext *avctx, |
432 |
void *data, int *data_size, |
433 |
const uint8_t *buf, int buf_size) |
434 |
{ |
435 |
/* Note, the only difference between the 15Bpp and 16Bpp */
|
436 |
/* Format is the pixel format, the packets are processed the same. */
|
437 |
FlicDecodeContext *s = avctx->priv_data; |
438 |
|
439 |
int stream_ptr = 0; |
440 |
int pixel_ptr;
|
441 |
unsigned char palette_idx1; |
442 |
|
443 |
unsigned int frame_size; |
444 |
int num_chunks;
|
445 |
|
446 |
unsigned int chunk_size; |
447 |
int chunk_type;
|
448 |
|
449 |
int i, j;
|
450 |
|
451 |
int lines;
|
452 |
int compressed_lines;
|
453 |
signed short line_packets; |
454 |
int y_ptr;
|
455 |
int byte_run;
|
456 |
int pixel_skip;
|
457 |
int pixel_countdown;
|
458 |
unsigned char *pixels; |
459 |
int pixel;
|
460 |
unsigned int pixel_limit; |
461 |
|
462 |
s->frame.reference = 1;
|
463 |
s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE; |
464 |
if (avctx->reget_buffer(avctx, &s->frame) < 0) { |
465 |
av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
|
466 |
return -1; |
467 |
} |
468 |
|
469 |
pixels = s->frame.data[0];
|
470 |
pixel_limit = s->avctx->height * s->frame.linesize[0];
|
471 |
|
472 |
frame_size = AV_RL32(&buf[stream_ptr]); |
473 |
stream_ptr += 6; /* skip the magic number */ |
474 |
num_chunks = AV_RL16(&buf[stream_ptr]); |
475 |
stream_ptr += 10; /* skip padding */ |
476 |
|
477 |
frame_size -= 16;
|
478 |
|
479 |
/* iterate through the chunks */
|
480 |
while ((frame_size > 0) && (num_chunks > 0)) { |
481 |
chunk_size = AV_RL32(&buf[stream_ptr]); |
482 |
stream_ptr += 4;
|
483 |
chunk_type = AV_RL16(&buf[stream_ptr]); |
484 |
stream_ptr += 2;
|
485 |
|
486 |
switch (chunk_type) {
|
487 |
case FLI_256_COLOR:
|
488 |
case FLI_COLOR:
|
489 |
/* For some reason, it seems that non-palettized flics do
|
490 |
* include one of these chunks in their first frame.
|
491 |
* Why I do not know, it seems rather extraneous. */
|
492 |
/* av_log(avctx, AV_LOG_ERROR, "Unexpected Palette chunk %d in non-paletised FLC\n",chunk_type);*/
|
493 |
stream_ptr = stream_ptr + chunk_size - 6;
|
494 |
break;
|
495 |
|
496 |
case FLI_DELTA:
|
497 |
case FLI_DTA_LC:
|
498 |
y_ptr = 0;
|
499 |
compressed_lines = AV_RL16(&buf[stream_ptr]); |
500 |
stream_ptr += 2;
|
501 |
while (compressed_lines > 0) { |
502 |
line_packets = AV_RL16(&buf[stream_ptr]); |
503 |
stream_ptr += 2;
|
504 |
if (line_packets < 0) { |
505 |
line_packets = -line_packets; |
506 |
y_ptr += line_packets * s->frame.linesize[0];
|
507 |
} else {
|
508 |
compressed_lines--; |
509 |
pixel_ptr = y_ptr; |
510 |
CHECK_PIXEL_PTR(0);
|
511 |
pixel_countdown = s->avctx->width; |
512 |
for (i = 0; i < line_packets; i++) { |
513 |
/* account for the skip bytes */
|
514 |
pixel_skip = buf[stream_ptr++]; |
515 |
pixel_ptr += (pixel_skip*2); /* Pixel is 2 bytes wide */ |
516 |
pixel_countdown -= pixel_skip; |
517 |
byte_run = (signed char)(buf[stream_ptr++]); |
518 |
if (byte_run < 0) { |
519 |
byte_run = -byte_run; |
520 |
pixel = AV_RL16(&buf[stream_ptr]); |
521 |
stream_ptr += 2;
|
522 |
CHECK_PIXEL_PTR(2 * byte_run);
|
523 |
for (j = 0; j < byte_run; j++, pixel_countdown -= 2) { |
524 |
*((signed short*)(&pixels[pixel_ptr])) = pixel; |
525 |
pixel_ptr += 2;
|
526 |
} |
527 |
} else {
|
528 |
CHECK_PIXEL_PTR(2 * byte_run);
|
529 |
for (j = 0; j < byte_run; j++, pixel_countdown--) { |
530 |
*((signed short*)(&pixels[pixel_ptr])) = AV_RL16(&buf[stream_ptr]); |
531 |
stream_ptr += 2;
|
532 |
pixel_ptr += 2;
|
533 |
} |
534 |
} |
535 |
} |
536 |
|
537 |
y_ptr += s->frame.linesize[0];
|
538 |
} |
539 |
} |
540 |
break;
|
541 |
|
542 |
case FLI_LC:
|
543 |
av_log(avctx, AV_LOG_ERROR, "Unexpected FLI_LC chunk in non-paletised FLC\n");
|
544 |
stream_ptr = stream_ptr + chunk_size - 6;
|
545 |
break;
|
546 |
|
547 |
case FLI_BLACK:
|
548 |
/* set the whole frame to 0x0000 which is black in both 15Bpp and 16Bpp modes. */
|
549 |
memset(pixels, 0x0000,
|
550 |
s->frame.linesize[0] * s->avctx->height);
|
551 |
break;
|
552 |
|
553 |
case FLI_BRUN:
|
554 |
y_ptr = 0;
|
555 |
for (lines = 0; lines < s->avctx->height; lines++) { |
556 |
pixel_ptr = y_ptr; |
557 |
/* disregard the line packets; instead, iterate through all
|
558 |
* pixels on a row */
|
559 |
stream_ptr++; |
560 |
pixel_countdown = (s->avctx->width * 2);
|
561 |
|
562 |
while (pixel_countdown > 0) { |
563 |
byte_run = (signed char)(buf[stream_ptr++]); |
564 |
if (byte_run > 0) { |
565 |
palette_idx1 = buf[stream_ptr++]; |
566 |
CHECK_PIXEL_PTR(byte_run); |
567 |
for (j = 0; j < byte_run; j++) { |
568 |
pixels[pixel_ptr++] = palette_idx1; |
569 |
pixel_countdown--; |
570 |
if (pixel_countdown < 0) |
571 |
av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) (linea%d)\n",
|
572 |
pixel_countdown, lines); |
573 |
} |
574 |
} else { /* copy bytes if byte_run < 0 */ |
575 |
byte_run = -byte_run; |
576 |
CHECK_PIXEL_PTR(byte_run); |
577 |
for (j = 0; j < byte_run; j++) { |
578 |
palette_idx1 = buf[stream_ptr++]; |
579 |
pixels[pixel_ptr++] = palette_idx1; |
580 |
pixel_countdown--; |
581 |
if (pixel_countdown < 0) |
582 |
av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n",
|
583 |
pixel_countdown, lines); |
584 |
} |
585 |
} |
586 |
} |
587 |
|
588 |
/* Now FLX is strange, in that it is "byte" as opposed to "pixel" run length compressed.
|
589 |
* This does not give us any good oportunity to perform word endian conversion
|
590 |
* during decompression. So if it is required (i.e., this is not a LE target, we do
|
591 |
* a second pass over the line here, swapping the bytes.
|
592 |
*/
|
593 |
#if HAVE_BIGENDIAN
|
594 |
pixel_ptr = y_ptr; |
595 |
pixel_countdown = s->avctx->width; |
596 |
while (pixel_countdown > 0) { |
597 |
*((signed short*)(&pixels[pixel_ptr])) = AV_RL16(&buf[pixel_ptr]); |
598 |
pixel_ptr += 2;
|
599 |
} |
600 |
#endif
|
601 |
y_ptr += s->frame.linesize[0];
|
602 |
} |
603 |
break;
|
604 |
|
605 |
case FLI_DTA_BRUN:
|
606 |
y_ptr = 0;
|
607 |
for (lines = 0; lines < s->avctx->height; lines++) { |
608 |
pixel_ptr = y_ptr; |
609 |
/* disregard the line packets; instead, iterate through all
|
610 |
* pixels on a row */
|
611 |
stream_ptr++; |
612 |
pixel_countdown = s->avctx->width; /* Width is in pixels, not bytes */
|
613 |
|
614 |
while (pixel_countdown > 0) { |
615 |
byte_run = (signed char)(buf[stream_ptr++]); |
616 |
if (byte_run > 0) { |
617 |
pixel = AV_RL16(&buf[stream_ptr]); |
618 |
stream_ptr += 2;
|
619 |
CHECK_PIXEL_PTR(2 * byte_run);
|
620 |
for (j = 0; j < byte_run; j++) { |
621 |
*((signed short*)(&pixels[pixel_ptr])) = pixel; |
622 |
pixel_ptr += 2;
|
623 |
pixel_countdown--; |
624 |
if (pixel_countdown < 0) |
625 |
av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n",
|
626 |
pixel_countdown); |
627 |
} |
628 |
} else { /* copy pixels if byte_run < 0 */ |
629 |
byte_run = -byte_run; |
630 |
CHECK_PIXEL_PTR(2 * byte_run);
|
631 |
for (j = 0; j < byte_run; j++) { |
632 |
*((signed short*)(&pixels[pixel_ptr])) = AV_RL16(&buf[stream_ptr]); |
633 |
stream_ptr += 2;
|
634 |
pixel_ptr += 2;
|
635 |
pixel_countdown--; |
636 |
if (pixel_countdown < 0) |
637 |
av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n",
|
638 |
pixel_countdown); |
639 |
} |
640 |
} |
641 |
} |
642 |
|
643 |
y_ptr += s->frame.linesize[0];
|
644 |
} |
645 |
break;
|
646 |
|
647 |
case FLI_COPY:
|
648 |
case FLI_DTA_COPY:
|
649 |
/* copy the chunk (uncompressed frame) */
|
650 |
if (chunk_size - 6 > (unsigned int)(s->avctx->width * s->avctx->height)*2) { |
651 |
av_log(avctx, AV_LOG_ERROR, "In chunk FLI_COPY : source data (%d bytes) " \
|
652 |
"bigger than image, skipping chunk\n", chunk_size - 6); |
653 |
stream_ptr += chunk_size - 6;
|
654 |
} else {
|
655 |
|
656 |
for (y_ptr = 0; y_ptr < s->frame.linesize[0] * s->avctx->height; |
657 |
y_ptr += s->frame.linesize[0]) {
|
658 |
|
659 |
pixel_countdown = s->avctx->width; |
660 |
pixel_ptr = 0;
|
661 |
while (pixel_countdown > 0) { |
662 |
*((signed short*)(&pixels[y_ptr + pixel_ptr])) = AV_RL16(&buf[stream_ptr+pixel_ptr]); |
663 |
pixel_ptr += 2;
|
664 |
pixel_countdown--; |
665 |
} |
666 |
stream_ptr += s->avctx->width*2;
|
667 |
} |
668 |
} |
669 |
break;
|
670 |
|
671 |
case FLI_MINI:
|
672 |
/* some sort of a thumbnail? disregard this chunk... */
|
673 |
stream_ptr += chunk_size - 6;
|
674 |
break;
|
675 |
|
676 |
default:
|
677 |
av_log(avctx, AV_LOG_ERROR, "Unrecognized chunk type: %d\n", chunk_type);
|
678 |
break;
|
679 |
} |
680 |
|
681 |
frame_size -= chunk_size; |
682 |
num_chunks--; |
683 |
} |
684 |
|
685 |
/* by the end of the chunk, the stream ptr should equal the frame
|
686 |
* size (minus 1, possibly); if it doesn't, issue a warning */
|
687 |
if ((stream_ptr != buf_size) && (stream_ptr != buf_size - 1)) |
688 |
av_log(avctx, AV_LOG_ERROR, "Processed FLI chunk where chunk size = %d " \
|
689 |
"and final chunk ptr = %d\n", buf_size, stream_ptr);
|
690 |
|
691 |
|
692 |
*data_size=sizeof(AVFrame);
|
693 |
*(AVFrame*)data = s->frame; |
694 |
|
695 |
return buf_size;
|
696 |
} |
697 |
|
698 |
static int flic_decode_frame_24BPP(AVCodecContext *avctx, |
699 |
void *data, int *data_size, |
700 |
const uint8_t *buf, int buf_size) |
701 |
{ |
702 |
av_log(avctx, AV_LOG_ERROR, "24Bpp FLC Unsupported due to lack of test files.\n");
|
703 |
return -1; |
704 |
} |
705 |
|
706 |
static int flic_decode_frame(AVCodecContext *avctx, |
707 |
void *data, int *data_size, |
708 |
AVPacket *avpkt) |
709 |
{ |
710 |
const uint8_t *buf = avpkt->data;
|
711 |
int buf_size = avpkt->size;
|
712 |
if (avctx->pix_fmt == PIX_FMT_PAL8) {
|
713 |
return flic_decode_frame_8BPP(avctx, data, data_size,
|
714 |
buf, buf_size); |
715 |
} |
716 |
else if ((avctx->pix_fmt == PIX_FMT_RGB555) || |
717 |
(avctx->pix_fmt == PIX_FMT_RGB565)) { |
718 |
return flic_decode_frame_15_16BPP(avctx, data, data_size,
|
719 |
buf, buf_size); |
720 |
} |
721 |
else if (avctx->pix_fmt == PIX_FMT_BGR24) { |
722 |
return flic_decode_frame_24BPP(avctx, data, data_size,
|
723 |
buf, buf_size); |
724 |
} |
725 |
|
726 |
/* Should not get here, ever as the pix_fmt is processed */
|
727 |
/* in flic_decode_init and the above if should deal with */
|
728 |
/* the finite set of possibilites allowable by here. */
|
729 |
/* But in case we do, just error out. */
|
730 |
av_log(avctx, AV_LOG_ERROR, "Unknown FLC format, my science cannot explain how this happened.\n");
|
731 |
return -1; |
732 |
} |
733 |
|
734 |
|
735 |
static av_cold int flic_decode_end(AVCodecContext *avctx) |
736 |
{ |
737 |
FlicDecodeContext *s = avctx->priv_data; |
738 |
|
739 |
if (s->frame.data[0]) |
740 |
avctx->release_buffer(avctx, &s->frame); |
741 |
|
742 |
return 0; |
743 |
} |
744 |
|
745 |
AVCodec ff_flic_decoder = { |
746 |
"flic",
|
747 |
AVMEDIA_TYPE_VIDEO, |
748 |
CODEC_ID_FLIC, |
749 |
sizeof(FlicDecodeContext),
|
750 |
flic_decode_init, |
751 |
NULL,
|
752 |
flic_decode_end, |
753 |
flic_decode_frame, |
754 |
CODEC_CAP_DR1, |
755 |
NULL,
|
756 |
NULL,
|
757 |
NULL,
|
758 |
NULL,
|
759 |
.long_name = NULL_IF_CONFIG_SMALL("Autodesk Animator Flic video"),
|
760 |
}; |