]> git.sesse.net Git - ffmpeg/blob - libavformat/flic.c
sweeping change from -EIO -> AVERROR_IO
[ffmpeg] / libavformat / flic.c
1 /*
2  * FLI/FLC Animation File Demuxer
3  * Copyright (c) 2003 The ffmpeg Project
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 /**
21  * @file flic.c
22  * FLI/FLC file demuxer
23  * by Mike Melanson (melanson@pcisys.net)
24  * for more information on the .fli/.flc file format and all of its many
25  * variations, visit:
26  *   http://www.compuphase.com/flic.htm
27  *
28  * This demuxer handles standard 0xAF11- and 0xAF12-type FLIs. It also
29  * handles special FLIs from the PC game "Magic Carpet".
30  */
31
32 #include "avformat.h"
33
34 #define FLIC_FILE_MAGIC_1 0xAF11
35 #define FLIC_FILE_MAGIC_2 0xAF12
36 #define FLIC_CHUNK_MAGIC_1 0xF1FA
37 #define FLIC_CHUNK_MAGIC_2 0xF5FA
38 #define FLIC_MC_PTS_INC 6000  /* pts increment for Magic Carpet game FLIs */
39 #define FLIC_DEFAULT_PTS_INC 6000  /* for FLIs that have 0 speed */
40
41 #define FLIC_HEADER_SIZE 128
42 #define FLIC_PREAMBLE_SIZE 6
43
44 typedef struct FlicDemuxContext {
45     int frame_pts_inc;
46     int64_t pts;
47     int video_stream_index;
48 } FlicDemuxContext;
49
50 static int flic_probe(AVProbeData *p)
51 {
52     int magic_number;
53
54     if (p->buf_size < 6)
55         return 0;
56
57     magic_number = LE_16(&p->buf[4]);
58     if ((magic_number != FLIC_FILE_MAGIC_1) &&
59         (magic_number != FLIC_FILE_MAGIC_2))
60         return 0;
61
62     return AVPROBE_SCORE_MAX;
63 }
64
65 static int flic_read_header(AVFormatContext *s,
66                             AVFormatParameters *ap)
67 {
68     FlicDemuxContext *flic = (FlicDemuxContext *)s->priv_data;
69     ByteIOContext *pb = &s->pb;
70     unsigned char header[FLIC_HEADER_SIZE];
71     AVStream *st;
72     int speed;
73     int magic_number;
74
75     flic->pts = 0;
76
77     /* load the whole header and pull out the width and height */
78     if (get_buffer(pb, header, FLIC_HEADER_SIZE) != FLIC_HEADER_SIZE)
79         return AVERROR_IO;
80
81     magic_number = LE_16(&header[4]);
82     speed = LE_32(&header[0x10]);
83
84     /* initialize the decoder streams */
85     st = av_new_stream(s, 0);
86     if (!st)
87         return AVERROR_NOMEM;
88     flic->video_stream_index = st->index;
89     st->codec.codec_type = CODEC_TYPE_VIDEO;
90     st->codec.codec_id = CODEC_ID_FLIC;
91     st->codec.codec_tag = 0;  /* no fourcc */
92     st->codec.width = LE_16(&header[0x08]);
93     st->codec.height = LE_16(&header[0x0A]);
94
95     if (!st->codec.width || !st->codec.height)
96         return AVERROR_INVALIDDATA;
97
98     /* send over the whole 128-byte FLIC header */
99     st->codec.extradata_size = FLIC_HEADER_SIZE;
100     st->codec.extradata = av_malloc(FLIC_HEADER_SIZE);
101     memcpy(st->codec.extradata, header, FLIC_HEADER_SIZE);
102
103     av_set_pts_info(st, 33, 1, 90000);
104
105     /* Time to figure out the framerate: If there is a FLIC chunk magic
106      * number at offset 0x10, assume this is from the Bullfrog game,
107      * Magic Carpet. */
108     if (LE_16(&header[0x10]) == FLIC_CHUNK_MAGIC_1) {
109
110         flic->frame_pts_inc = FLIC_MC_PTS_INC;
111
112         /* rewind the stream since the first chunk is at offset 12 */
113         url_fseek(pb, 12, SEEK_SET);
114
115         /* send over abbreviated FLIC header chunk */
116         av_free(st->codec.extradata);
117         st->codec.extradata_size = 12;
118         st->codec.extradata = av_malloc(12);
119         memcpy(st->codec.extradata, header, 12);
120
121     } else if (magic_number == FLIC_FILE_MAGIC_1) {
122         /*
123          * in this case, the speed (n) is number of 1/70s ticks between frames:
124          *
125          *    pts        n * frame #
126          *  --------  =  -----------  => pts = n * (90000/70) * frame #
127          *   90000           70
128          *
129          *  therefore, the frame pts increment = n * 1285.7
130          */
131         flic->frame_pts_inc = speed * 1285.7;
132     } else if (magic_number == FLIC_FILE_MAGIC_2) {
133         /*
134          * in this case, the speed (n) is number of milliseconds between frames:
135          *
136          *    pts        n * frame #
137          *  --------  =  -----------  => pts = n * 90 * frame #
138          *   90000          1000
139          *
140          *  therefore, the frame pts increment = n * 90
141          */
142         flic->frame_pts_inc = speed * 90;
143     } else
144         return AVERROR_INVALIDDATA;
145
146     if (flic->frame_pts_inc == 0)
147         flic->frame_pts_inc = FLIC_DEFAULT_PTS_INC;
148
149     return 0;
150 }
151
152 static int flic_read_packet(AVFormatContext *s,
153                             AVPacket *pkt)
154 {
155     FlicDemuxContext *flic = (FlicDemuxContext *)s->priv_data;
156     ByteIOContext *pb = &s->pb;
157     int packet_read = 0;
158     unsigned int size;
159     int magic;
160     int ret = 0;
161     unsigned char preamble[FLIC_PREAMBLE_SIZE];
162
163     while (!packet_read) {
164
165         if ((ret = get_buffer(pb, preamble, FLIC_PREAMBLE_SIZE)) !=
166             FLIC_PREAMBLE_SIZE) {
167             ret = AVERROR_IO;
168             break;
169         }
170
171         size = LE_32(&preamble[0]);
172         magic = LE_16(&preamble[4]);
173
174         if ((magic == FLIC_CHUNK_MAGIC_1) || (magic == FLIC_CHUNK_MAGIC_2)) {
175             if (av_new_packet(pkt, size)) {
176                 ret = AVERROR_IO;
177                 break;
178             }
179             pkt->stream_index = flic->video_stream_index;
180             pkt->pts = flic->pts;
181             memcpy(pkt->data, preamble, FLIC_PREAMBLE_SIZE);
182             ret = get_buffer(pb, pkt->data + FLIC_PREAMBLE_SIZE, 
183                 size - FLIC_PREAMBLE_SIZE);
184             if (ret != size - FLIC_PREAMBLE_SIZE) {
185                 av_free_packet(pkt);
186                 ret = AVERROR_IO;
187             }
188             flic->pts += flic->frame_pts_inc;
189             packet_read = 1;
190         } else {
191             /* not interested in this chunk */
192             url_fseek(pb, size - 6, SEEK_CUR);
193         }
194     }
195
196     return ret;
197 }
198
199 static int flic_read_close(AVFormatContext *s)
200 {
201 //    FlicDemuxContext *flic = (FlicDemuxContext *)s->priv_data;
202
203     return 0;
204 }
205
206 static AVInputFormat flic_iformat = {
207     "flic",
208     "FLI/FLC animation format",
209     sizeof(FlicDemuxContext),
210     flic_probe,
211     flic_read_header,
212     flic_read_packet,
213     flic_read_close,
214 };
215
216 int flic_init(void)
217 {
218     av_register_input_format(&flic_iformat);
219     return 0;
220 }