~ubuntu-branches/ubuntu/utopic/libav/utopic

« back to all changes in this revision

Viewing changes to libavformat/flic.c

  • Committer: Bazaar Package Importer
  • Author(s): Reinhard Tartler
  • Date: 2011-03-20 12:09:31 UTC
  • Revision ID: james.westby@ubuntu.com-20110320120931-nfhi9tiok27gxhw1
Tags: upstream-0.6.2
ImportĀ upstreamĀ versionĀ 0.6.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * FLI/FLC Animation File Demuxer
 
3
 * Copyright (c) 2003 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
 * 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
 
27
 * variations, visit:
 
28
 *   http://www.compuphase.com/flic.htm
 
29
 *
 
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".
 
32
 */
 
33
 
 
34
#include "libavutil/intreadwrite.h"
 
35
#include "avformat.h"
 
36
 
 
37
#define FLIC_FILE_MAGIC_1 0xAF11
 
38
#define FLIC_FILE_MAGIC_2 0xAF12
 
39
#define FLIC_FILE_MAGIC_3 0xAF44  /* Flic Type for Extended FLX Format which
 
40
                                     originated in Dave's Targa Animator (DTA) */
 
41
#define FLIC_CHUNK_MAGIC_1 0xF1FA
 
42
#define FLIC_CHUNK_MAGIC_2 0xF5FA
 
43
#define FLIC_MC_SPEED 5  /* speed for Magic Carpet game FLIs */
 
44
#define FLIC_DEFAULT_SPEED 5  /* for FLIs that have 0 speed */
 
45
#define FLIC_TFTD_CHUNK_AUDIO 0xAAAA /* Audio chunk. Used in Terror from the Deep.
 
46
                                        Has 10 B extra header not accounted for in the chunk header */
 
47
#define FLIC_TFTD_SAMPLE_RATE 22050
 
48
 
 
49
#define FLIC_HEADER_SIZE 128
 
50
#define FLIC_PREAMBLE_SIZE 6
 
51
 
 
52
typedef struct FlicDemuxContext {
 
53
    int video_stream_index;
 
54
    int audio_stream_index;
 
55
    int frame_number;
 
56
} FlicDemuxContext;
 
57
 
 
58
static int flic_probe(AVProbeData *p)
 
59
{
 
60
    int magic_number;
 
61
 
 
62
    if(p->buf_size < FLIC_HEADER_SIZE)
 
63
        return 0;
 
64
 
 
65
    magic_number = AV_RL16(&p->buf[4]);
 
66
    if ((magic_number != FLIC_FILE_MAGIC_1) &&
 
67
        (magic_number != FLIC_FILE_MAGIC_2) &&
 
68
        (magic_number != FLIC_FILE_MAGIC_3))
 
69
        return 0;
 
70
 
 
71
    if(AV_RL16(&p->buf[0x10]) != FLIC_CHUNK_MAGIC_1){
 
72
        if(AV_RL32(&p->buf[0x10]) > 2000)
 
73
            return 0;
 
74
    }
 
75
 
 
76
    if(   AV_RL16(&p->buf[0x08]) > 4096
 
77
       || AV_RL16(&p->buf[0x0A]) > 4096)
 
78
        return 0;
 
79
 
 
80
 
 
81
    return AVPROBE_SCORE_MAX;
 
82
}
 
83
 
 
84
static int flic_read_header(AVFormatContext *s,
 
85
                            AVFormatParameters *ap)
 
86
{
 
87
    FlicDemuxContext *flic = s->priv_data;
 
88
    ByteIOContext *pb = s->pb;
 
89
    unsigned char header[FLIC_HEADER_SIZE];
 
90
    AVStream *st, *ast;
 
91
    int speed;
 
92
    int magic_number;
 
93
    unsigned char preamble[FLIC_PREAMBLE_SIZE];
 
94
 
 
95
    flic->frame_number = 0;
 
96
 
 
97
    /* load the whole header and pull out the width and height */
 
98
    if (get_buffer(pb, header, FLIC_HEADER_SIZE) != FLIC_HEADER_SIZE)
 
99
        return AVERROR(EIO);
 
100
 
 
101
    magic_number = AV_RL16(&header[4]);
 
102
    speed = AV_RL32(&header[0x10]);
 
103
    if (speed == 0)
 
104
        speed = FLIC_DEFAULT_SPEED;
 
105
 
 
106
    /* initialize the decoder streams */
 
107
    st = av_new_stream(s, 0);
 
108
    if (!st)
 
109
        return AVERROR(ENOMEM);
 
110
    flic->video_stream_index = st->index;
 
111
    st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
 
112
    st->codec->codec_id = CODEC_ID_FLIC;
 
113
    st->codec->codec_tag = 0;  /* no fourcc */
 
114
    st->codec->width = AV_RL16(&header[0x08]);
 
115
    st->codec->height = AV_RL16(&header[0x0A]);
 
116
 
 
117
    if (!st->codec->width || !st->codec->height) {
 
118
        /* Ugly hack needed for the following sample: */
 
119
        /* http://samples.mplayerhq.hu/fli-flc/fli-bugs/specular.flc */
 
120
        av_log(s, AV_LOG_WARNING,
 
121
               "File with no specified width/height. Trying 640x480.\n");
 
122
        st->codec->width  = 640;
 
123
        st->codec->height = 480;
 
124
    }
 
125
 
 
126
    /* send over the whole 128-byte FLIC header */
 
127
    st->codec->extradata_size = FLIC_HEADER_SIZE;
 
128
    st->codec->extradata = av_malloc(FLIC_HEADER_SIZE);
 
129
    memcpy(st->codec->extradata, header, FLIC_HEADER_SIZE);
 
130
 
 
131
    /* peek at the preamble to detect TFTD videos - they seem to always start with an audio chunk */
 
132
    if (get_buffer(pb, preamble, FLIC_PREAMBLE_SIZE) != FLIC_PREAMBLE_SIZE) {
 
133
        av_log(s, AV_LOG_ERROR, "Failed to peek at preamble\n");
 
134
        return AVERROR(EIO);
 
135
    }
 
136
 
 
137
    url_fseek(pb, -FLIC_PREAMBLE_SIZE, SEEK_CUR);
 
138
 
 
139
    /* Time to figure out the framerate:
 
140
     * If the first preamble's magic number is 0xAAAA then this file is from
 
141
     * X-COM: Terror from the Deep. If on the other hand there is a FLIC chunk
 
142
     * magic number at offset 0x10 assume this file is from Magic Carpet instead.
 
143
     * If neither of the above is true then this is a normal FLIC file.
 
144
     */
 
145
    if (AV_RL16(&preamble[4]) == FLIC_TFTD_CHUNK_AUDIO) {
 
146
        /* TFTD videos have an extra 22050 Hz 8-bit mono audio stream */
 
147
        ast = av_new_stream(s, 1);
 
148
        if (!ast)
 
149
            return AVERROR(ENOMEM);
 
150
 
 
151
        flic->audio_stream_index = ast->index;
 
152
 
 
153
        /* all audio frames are the same size, so use the size of the first chunk for block_align */
 
154
        ast->codec->block_align = AV_RL32(&preamble[0]);
 
155
        ast->codec->codec_type = CODEC_TYPE_AUDIO;
 
156
        ast->codec->codec_id = CODEC_ID_PCM_U8;
 
157
        ast->codec->codec_tag = 0;
 
158
        ast->codec->sample_rate = FLIC_TFTD_SAMPLE_RATE;
 
159
        ast->codec->channels = 1;
 
160
        ast->codec->sample_fmt = SAMPLE_FMT_U8;
 
161
        ast->codec->bit_rate = st->codec->sample_rate * 8;
 
162
        ast->codec->bits_per_coded_sample = 8;
 
163
        ast->codec->channel_layout = CH_LAYOUT_MONO;
 
164
        ast->codec->extradata_size = 0;
 
165
 
 
166
        /* Since the header information is incorrect we have to figure out the
 
167
         * framerate using block_align and the fact that the audio is 22050 Hz.
 
168
         * We usually have two cases: 2205 -> 10 fps and 1470 -> 15 fps */
 
169
        av_set_pts_info(st, 64, ast->codec->block_align, FLIC_TFTD_SAMPLE_RATE);
 
170
        av_set_pts_info(ast, 64, 1, FLIC_TFTD_SAMPLE_RATE);
 
171
    } else if (AV_RL16(&header[0x10]) == FLIC_CHUNK_MAGIC_1) {
 
172
        av_set_pts_info(st, 64, FLIC_MC_SPEED, 70);
 
173
 
 
174
        /* rewind the stream since the first chunk is at offset 12 */
 
175
        url_fseek(pb, 12, SEEK_SET);
 
176
 
 
177
        /* send over abbreviated FLIC header chunk */
 
178
        av_free(st->codec->extradata);
 
179
        st->codec->extradata_size = 12;
 
180
        st->codec->extradata = av_malloc(12);
 
181
        memcpy(st->codec->extradata, header, 12);
 
182
 
 
183
    } else if (magic_number == FLIC_FILE_MAGIC_1) {
 
184
        av_set_pts_info(st, 64, speed, 70);
 
185
    } else if ((magic_number == FLIC_FILE_MAGIC_2) ||
 
186
               (magic_number == FLIC_FILE_MAGIC_3)) {
 
187
        av_set_pts_info(st, 64, speed, 1000);
 
188
    } else {
 
189
        av_log(s, AV_LOG_INFO, "Invalid or unsupported magic chunk in file\n");
 
190
        return AVERROR_INVALIDDATA;
 
191
    }
 
192
 
 
193
    return 0;
 
194
}
 
195
 
 
196
static int flic_read_packet(AVFormatContext *s,
 
197
                            AVPacket *pkt)
 
198
{
 
199
    FlicDemuxContext *flic = s->priv_data;
 
200
    ByteIOContext *pb = s->pb;
 
201
    int packet_read = 0;
 
202
    unsigned int size;
 
203
    int magic;
 
204
    int ret = 0;
 
205
    unsigned char preamble[FLIC_PREAMBLE_SIZE];
 
206
 
 
207
    while (!packet_read) {
 
208
 
 
209
        if ((ret = get_buffer(pb, preamble, FLIC_PREAMBLE_SIZE)) !=
 
210
            FLIC_PREAMBLE_SIZE) {
 
211
            ret = AVERROR(EIO);
 
212
            break;
 
213
        }
 
214
 
 
215
        size = AV_RL32(&preamble[0]);
 
216
        magic = AV_RL16(&preamble[4]);
 
217
 
 
218
        if (((magic == FLIC_CHUNK_MAGIC_1) || (magic == FLIC_CHUNK_MAGIC_2)) && size > FLIC_PREAMBLE_SIZE) {
 
219
            if (av_new_packet(pkt, size)) {
 
220
                ret = AVERROR(EIO);
 
221
                break;
 
222
            }
 
223
            pkt->stream_index = flic->video_stream_index;
 
224
            pkt->pts = flic->frame_number++;
 
225
            pkt->pos = url_ftell(pb);
 
226
            memcpy(pkt->data, preamble, FLIC_PREAMBLE_SIZE);
 
227
            ret = get_buffer(pb, pkt->data + FLIC_PREAMBLE_SIZE,
 
228
                size - FLIC_PREAMBLE_SIZE);
 
229
            if (ret != size - FLIC_PREAMBLE_SIZE) {
 
230
                av_free_packet(pkt);
 
231
                ret = AVERROR(EIO);
 
232
            }
 
233
            packet_read = 1;
 
234
        } else if (magic == FLIC_TFTD_CHUNK_AUDIO) {
 
235
            if (av_new_packet(pkt, size)) {
 
236
                ret = AVERROR(EIO);
 
237
                break;
 
238
            }
 
239
 
 
240
            /* skip useless 10B sub-header (yes, it's not accounted for in the chunk header) */
 
241
            url_fseek(pb, 10, SEEK_CUR);
 
242
 
 
243
            pkt->stream_index = flic->audio_stream_index;
 
244
            pkt->pos = url_ftell(pb);
 
245
            ret = get_buffer(pb, pkt->data, size);
 
246
 
 
247
            if (ret != size) {
 
248
                av_free_packet(pkt);
 
249
                ret = AVERROR(EIO);
 
250
            }
 
251
 
 
252
            packet_read = 1;
 
253
        } else {
 
254
            /* not interested in this chunk */
 
255
            url_fseek(pb, size - 6, SEEK_CUR);
 
256
        }
 
257
    }
 
258
 
 
259
    return ret;
 
260
}
 
261
 
 
262
AVInputFormat flic_demuxer = {
 
263
    "flic",
 
264
    NULL_IF_CONFIG_SMALL("FLI/FLC/FLX animation format"),
 
265
    sizeof(FlicDemuxContext),
 
266
    flic_probe,
 
267
    flic_read_header,
 
268
    flic_read_packet,
 
269
};