2 * FLI/FLC Animation File Demuxer
3 * Copyright (c) 2003 The FFmpeg project
5 * This file is part of FFmpeg.
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.
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.
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
24 * FLI/FLC file demuxer
25 * by Mike Melanson (melanson@pcisys.net)
26 * for more information on the .fli/.flc file format and all of its many
28 * http://www.compuphase.com/flic.htm
30 * This demuxer handles standard 0xAF11- and 0xAF12-type FLIs. It also handles
31 * special FLIs from the PC games "Magic Carpet" and "X-COM: Terror from the Deep".
34 #include "libavutil/channel_layout.h"
35 #include "libavutil/intreadwrite.h"
37 #include "avio_internal.h"
41 #define FLIC_FILE_MAGIC_1 0xAF11
42 #define FLIC_FILE_MAGIC_2 0xAF12
43 #define FLIC_FILE_MAGIC_3 0xAF44 /* Flic Type for Extended FLX Format which
44 originated in Dave's Targa Animator (DTA) */
45 #define FLIC_CHUNK_MAGIC_1 0xF1FA
46 #define FLIC_CHUNK_MAGIC_2 0xF5FA
47 #define FLIC_MC_SPEED 5 /* speed for Magic Carpet game FLIs */
48 #define FLIC_DEFAULT_SPEED 5 /* for FLIs that have 0 speed */
49 #define FLIC_TFTD_CHUNK_AUDIO 0xAAAA /* Audio chunk. Used in Terror from the Deep.
50 Has 10 B extra header not accounted for in the chunk header */
51 #define FLIC_TFTD_SAMPLE_RATE 22050
53 #define FLIC_HEADER_SIZE 128
54 #define FLIC_PREAMBLE_SIZE 6
56 typedef struct FlicDemuxContext
{
57 int video_stream_index
;
58 int audio_stream_index
;
62 static int flic_probe(const AVProbeData
*p
)
66 if(p
->buf_size
< FLIC_HEADER_SIZE
)
69 magic_number
= AV_RL16(&p
->buf
[4]);
70 if ((magic_number
!= FLIC_FILE_MAGIC_1
) &&
71 (magic_number
!= FLIC_FILE_MAGIC_2
) &&
72 (magic_number
!= FLIC_FILE_MAGIC_3
))
75 if(AV_RL16(&p
->buf
[0x10]) != FLIC_CHUNK_MAGIC_1
){
76 if(AV_RL32(&p
->buf
[0x10]) > 2000)
80 if( AV_RL16(&p
->buf
[0x08]) > 4096
81 || AV_RL16(&p
->buf
[0x0A]) > 4096)
85 return AVPROBE_SCORE_MAX
- 1;
88 static int flic_read_header(AVFormatContext
*s
)
90 FlicDemuxContext
*flic
= s
->priv_data
;
91 AVIOContext
*pb
= s
->pb
;
92 unsigned char header
[FLIC_HEADER_SIZE
];
96 unsigned char preamble
[FLIC_PREAMBLE_SIZE
];
98 flic
->frame_number
= 0;
100 /* load the whole header and pull out the width and height */
101 if ((ret
= ffio_read_size(pb
, header
, FLIC_HEADER_SIZE
)) < 0)
104 magic_number
= AV_RL16(&header
[4]);
105 speed
= AV_RL32(&header
[0x10]);
107 speed
= FLIC_DEFAULT_SPEED
;
109 /* initialize the decoder streams */
110 st
= avformat_new_stream(s
, NULL
);
112 return AVERROR(ENOMEM
);
113 flic
->video_stream_index
= st
->index
;
114 st
->codecpar
->codec_type
= AVMEDIA_TYPE_VIDEO
;
115 st
->codecpar
->codec_id
= AV_CODEC_ID_FLIC
;
116 st
->codecpar
->codec_tag
= 0; /* no fourcc */
117 st
->codecpar
->width
= AV_RL16(&header
[0x08]);
118 st
->codecpar
->height
= AV_RL16(&header
[0x0A]);
120 if (!st
->codecpar
->width
|| !st
->codecpar
->height
) {
121 /* Ugly hack needed for the following sample: */
122 /* http://samples.mplayerhq.hu/fli-flc/fli-bugs/specular.flc */
123 av_log(s
, AV_LOG_WARNING
,
124 "File with no specified width/height. Trying 640x480.\n");
125 st
->codecpar
->width
= 640;
126 st
->codecpar
->height
= 480;
129 /* send over the whole 128-byte FLIC header */
130 if ((ret
= ff_alloc_extradata(st
->codecpar
, FLIC_HEADER_SIZE
)) < 0)
132 memcpy(st
->codecpar
->extradata
, header
, FLIC_HEADER_SIZE
);
134 /* peek at the preamble to detect TFTD videos - they seem to always start with an audio chunk */
135 if ((ret
= ffio_read_size(pb
, preamble
, FLIC_PREAMBLE_SIZE
)) < 0) {
136 av_log(s
, AV_LOG_ERROR
, "Failed to peek at preamble\n");
140 avio_seek(pb
, -FLIC_PREAMBLE_SIZE
, SEEK_CUR
);
142 /* Time to figure out the framerate:
143 * If the first preamble's magic number is 0xAAAA then this file is from
144 * X-COM: Terror from the Deep. If on the other hand there is a FLIC chunk
145 * magic number at offset 0x10 assume this file is from Magic Carpet instead.
146 * If neither of the above is true then this is a normal FLIC file.
148 if (AV_RL16(&preamble
[4]) == FLIC_TFTD_CHUNK_AUDIO
) {
149 /* TFTD videos have an extra 22050 Hz 8-bit mono audio stream */
150 ast
= avformat_new_stream(s
, NULL
);
152 return AVERROR(ENOMEM
);
154 flic
->audio_stream_index
= ast
->index
;
156 /* all audio frames are the same size, so use the size of the first chunk for block_align */
157 ast
->codecpar
->block_align
= AV_RL32(&preamble
[0]);
158 ast
->codecpar
->codec_type
= AVMEDIA_TYPE_AUDIO
;
159 ast
->codecpar
->codec_id
= AV_CODEC_ID_PCM_U8
;
160 ast
->codecpar
->codec_tag
= 0;
161 ast
->codecpar
->sample_rate
= FLIC_TFTD_SAMPLE_RATE
;
162 ast
->codecpar
->bit_rate
= st
->codecpar
->sample_rate
* 8;
163 ast
->codecpar
->bits_per_coded_sample
= 8;
164 ast
->codecpar
->ch_layout
= (AVChannelLayout
)AV_CHANNEL_LAYOUT_MONO
;
165 ast
->codecpar
->extradata_size
= 0;
167 /* Since the header information is incorrect we have to figure out the
168 * framerate using block_align and the fact that the audio is 22050 Hz.
169 * We usually have two cases: 2205 -> 10 fps and 1470 -> 15 fps */
170 avpriv_set_pts_info(st
, 64, ast
->codecpar
->block_align
, FLIC_TFTD_SAMPLE_RATE
);
171 avpriv_set_pts_info(ast
, 64, 1, FLIC_TFTD_SAMPLE_RATE
);
172 } else if (AV_RL16(&header
[0x10]) == FLIC_CHUNK_MAGIC_1
) {
173 avpriv_set_pts_info(st
, 64, FLIC_MC_SPEED
, 70);
175 /* rewind the stream since the first chunk is at offset 12 */
176 avio_seek(pb
, 12, SEEK_SET
);
178 /* send over abbreviated FLIC header chunk */
179 if ((ret
= ff_alloc_extradata(st
->codecpar
, 12)) < 0)
181 memcpy(st
->codecpar
->extradata
, header
, 12);
183 } else if (magic_number
== FLIC_FILE_MAGIC_1
) {
184 avpriv_set_pts_info(st
, 64, speed
, 70);
185 } else if ((magic_number
== FLIC_FILE_MAGIC_2
) ||
186 (magic_number
== FLIC_FILE_MAGIC_3
)) {
187 avpriv_set_pts_info(st
, 64, speed
, 1000);
189 av_log(s
, AV_LOG_ERROR
, "Invalid or unsupported magic chunk in file\n");
190 return AVERROR_INVALIDDATA
;
196 static int flic_read_packet(AVFormatContext
*s
,
199 FlicDemuxContext
*flic
= s
->priv_data
;
200 AVIOContext
*pb
= s
->pb
;
205 unsigned char preamble
[FLIC_PREAMBLE_SIZE
];
206 int64_t pos
= avio_tell(pb
);
208 while (!packet_read
&& !avio_feof(pb
)) {
210 if ((ret
= ffio_read_size(pb
, preamble
, FLIC_PREAMBLE_SIZE
)) < 0)
213 size
= AV_RL32(&preamble
[0]);
214 magic
= AV_RL16(&preamble
[4]);
216 if (((magic
== FLIC_CHUNK_MAGIC_1
) || (magic
== FLIC_CHUNK_MAGIC_2
)) && size
> FLIC_PREAMBLE_SIZE
) {
217 if ((ret
= av_new_packet(pkt
, size
)) < 0)
220 pkt
->stream_index
= flic
->video_stream_index
;
222 memcpy(pkt
->data
, preamble
, FLIC_PREAMBLE_SIZE
);
223 ret
= ffio_read_size(pb
, pkt
->data
+ FLIC_PREAMBLE_SIZE
,
224 size
- FLIC_PREAMBLE_SIZE
);
225 pkt
->flags
= flic
->frame_number
== 0 ? AV_PKT_FLAG_KEY
: 0;
226 pkt
->pts
= flic
->frame_number
;
227 if (flic
->frame_number
== 0)
228 av_add_index_entry(s
->streams
[flic
->video_stream_index
], pkt
->pos
, pkt
->pts
, pkt
->size
, 0, AVINDEX_KEYFRAME
);
230 flic
->frame_number
++;
231 } else if (magic
== FLIC_TFTD_CHUNK_AUDIO
) {
232 if ((ret
= av_new_packet(pkt
, size
)) < 0)
235 /* skip useless 10B sub-header (yes, it's not accounted for in the chunk header) */
238 pkt
->stream_index
= flic
->audio_stream_index
;
240 pkt
->flags
= AV_PKT_FLAG_KEY
;
241 ret
= ffio_read_size(pb
, pkt
->data
, size
);
248 /* not interested in this chunk */
249 avio_skip(pb
, size
- 6);
253 return avio_feof(pb
) ? AVERROR_EOF
: ret
;
256 static int flic_read_seek(AVFormatContext
*s
, int stream_index
,
257 int64_t pts
, int flags
)
259 FlicDemuxContext
*flic
= s
->priv_data
;
260 AVStream
*st
= s
->streams
[stream_index
];
261 FFStream
*const sti
= ffstream(st
);
265 if (!sti
->index_entries
|| stream_index
!= flic
->video_stream_index
)
268 index
= av_index_search_timestamp(st
, pts
, flags
);
271 index
= av_index_search_timestamp(st
, pts
, flags
^ AVSEEK_FLAG_BACKWARD
);
275 pos
= sti
->index_entries
[index
].pos
;
276 ts
= sti
->index_entries
[index
].timestamp
;
277 flic
->frame_number
= ts
;
278 avio_seek(s
->pb
, pos
, SEEK_SET
);
282 const FFInputFormat ff_flic_demuxer
= {
284 .p
.long_name
= NULL_IF_CONFIG_SMALL("FLI/FLC/FLX animation"),
285 .priv_data_size
= sizeof(FlicDemuxContext
),
286 .read_probe
= flic_probe
,
287 .read_header
= flic_read_header
,
288 .read_packet
= flic_read_packet
,
289 .read_seek
= flic_read_seek
,