Libav 0.7.1
|
00001 /* 00002 * FLI/FLC Animation File Demuxer 00003 * Copyright (c) 2003 The ffmpeg Project 00004 * 00005 * This file is part of Libav. 00006 * 00007 * Libav is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * Libav is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with Libav; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00020 */ 00021 00034 #include "libavutil/intreadwrite.h" 00035 #include "libavutil/audioconvert.h" 00036 #include "avformat.h" 00037 00038 #define FLIC_FILE_MAGIC_1 0xAF11 00039 #define FLIC_FILE_MAGIC_2 0xAF12 00040 #define FLIC_FILE_MAGIC_3 0xAF44 /* Flic Type for Extended FLX Format which 00041 originated in Dave's Targa Animator (DTA) */ 00042 #define FLIC_CHUNK_MAGIC_1 0xF1FA 00043 #define FLIC_CHUNK_MAGIC_2 0xF5FA 00044 #define FLIC_MC_SPEED 5 /* speed for Magic Carpet game FLIs */ 00045 #define FLIC_DEFAULT_SPEED 5 /* for FLIs that have 0 speed */ 00046 #define FLIC_TFTD_CHUNK_AUDIO 0xAAAA /* Audio chunk. Used in Terror from the Deep. 00047 Has 10 B extra header not accounted for in the chunk header */ 00048 #define FLIC_TFTD_SAMPLE_RATE 22050 00049 00050 #define FLIC_HEADER_SIZE 128 00051 #define FLIC_PREAMBLE_SIZE 6 00052 00053 typedef struct FlicDemuxContext { 00054 int video_stream_index; 00055 int audio_stream_index; 00056 int frame_number; 00057 } FlicDemuxContext; 00058 00059 static int flic_probe(AVProbeData *p) 00060 { 00061 int magic_number; 00062 00063 if(p->buf_size < FLIC_HEADER_SIZE) 00064 return 0; 00065 00066 magic_number = AV_RL16(&p->buf[4]); 00067 if ((magic_number != FLIC_FILE_MAGIC_1) && 00068 (magic_number != FLIC_FILE_MAGIC_2) && 00069 (magic_number != FLIC_FILE_MAGIC_3)) 00070 return 0; 00071 00072 if(AV_RL16(&p->buf[0x10]) != FLIC_CHUNK_MAGIC_1){ 00073 if(AV_RL32(&p->buf[0x10]) > 2000) 00074 return 0; 00075 } 00076 00077 if( AV_RL16(&p->buf[0x08]) > 4096 00078 || AV_RL16(&p->buf[0x0A]) > 4096) 00079 return 0; 00080 00081 00082 return AVPROBE_SCORE_MAX; 00083 } 00084 00085 static int flic_read_header(AVFormatContext *s, 00086 AVFormatParameters *ap) 00087 { 00088 FlicDemuxContext *flic = s->priv_data; 00089 AVIOContext *pb = s->pb; 00090 unsigned char header[FLIC_HEADER_SIZE]; 00091 AVStream *st, *ast; 00092 int speed; 00093 int magic_number; 00094 unsigned char preamble[FLIC_PREAMBLE_SIZE]; 00095 00096 flic->frame_number = 0; 00097 00098 /* load the whole header and pull out the width and height */ 00099 if (avio_read(pb, header, FLIC_HEADER_SIZE) != FLIC_HEADER_SIZE) 00100 return AVERROR(EIO); 00101 00102 magic_number = AV_RL16(&header[4]); 00103 speed = AV_RL32(&header[0x10]); 00104 if (speed == 0) 00105 speed = FLIC_DEFAULT_SPEED; 00106 00107 /* initialize the decoder streams */ 00108 st = av_new_stream(s, 0); 00109 if (!st) 00110 return AVERROR(ENOMEM); 00111 flic->video_stream_index = st->index; 00112 st->codec->codec_type = AVMEDIA_TYPE_VIDEO; 00113 st->codec->codec_id = CODEC_ID_FLIC; 00114 st->codec->codec_tag = 0; /* no fourcc */ 00115 st->codec->width = AV_RL16(&header[0x08]); 00116 st->codec->height = AV_RL16(&header[0x0A]); 00117 00118 if (!st->codec->width || !st->codec->height) { 00119 /* Ugly hack needed for the following sample: */ 00120 /* http://samples.libav.org/fli-flc/fli-bugs/specular.flc */ 00121 av_log(s, AV_LOG_WARNING, 00122 "File with no specified width/height. Trying 640x480.\n"); 00123 st->codec->width = 640; 00124 st->codec->height = 480; 00125 } 00126 00127 /* send over the whole 128-byte FLIC header */ 00128 st->codec->extradata_size = FLIC_HEADER_SIZE; 00129 st->codec->extradata = av_malloc(FLIC_HEADER_SIZE); 00130 memcpy(st->codec->extradata, header, FLIC_HEADER_SIZE); 00131 00132 /* peek at the preamble to detect TFTD videos - they seem to always start with an audio chunk */ 00133 if (avio_read(pb, preamble, FLIC_PREAMBLE_SIZE) != FLIC_PREAMBLE_SIZE) { 00134 av_log(s, AV_LOG_ERROR, "Failed to peek at preamble\n"); 00135 return AVERROR(EIO); 00136 } 00137 00138 avio_seek(pb, -FLIC_PREAMBLE_SIZE, SEEK_CUR); 00139 00140 /* Time to figure out the framerate: 00141 * If the first preamble's magic number is 0xAAAA then this file is from 00142 * X-COM: Terror from the Deep. If on the other hand there is a FLIC chunk 00143 * magic number at offset 0x10 assume this file is from Magic Carpet instead. 00144 * If neither of the above is true then this is a normal FLIC file. 00145 */ 00146 if (AV_RL16(&preamble[4]) == FLIC_TFTD_CHUNK_AUDIO) { 00147 /* TFTD videos have an extra 22050 Hz 8-bit mono audio stream */ 00148 ast = av_new_stream(s, 1); 00149 if (!ast) 00150 return AVERROR(ENOMEM); 00151 00152 flic->audio_stream_index = ast->index; 00153 00154 /* all audio frames are the same size, so use the size of the first chunk for block_align */ 00155 ast->codec->block_align = AV_RL32(&preamble[0]); 00156 ast->codec->codec_type = AVMEDIA_TYPE_AUDIO; 00157 ast->codec->codec_id = CODEC_ID_PCM_U8; 00158 ast->codec->codec_tag = 0; 00159 ast->codec->sample_rate = FLIC_TFTD_SAMPLE_RATE; 00160 ast->codec->channels = 1; 00161 ast->codec->sample_fmt = AV_SAMPLE_FMT_U8; 00162 ast->codec->bit_rate = st->codec->sample_rate * 8; 00163 ast->codec->bits_per_coded_sample = 8; 00164 ast->codec->channel_layout = AV_CH_LAYOUT_MONO; 00165 ast->codec->extradata_size = 0; 00166 00167 /* Since the header information is incorrect we have to figure out the 00168 * framerate using block_align and the fact that the audio is 22050 Hz. 00169 * We usually have two cases: 2205 -> 10 fps and 1470 -> 15 fps */ 00170 av_set_pts_info(st, 64, ast->codec->block_align, FLIC_TFTD_SAMPLE_RATE); 00171 av_set_pts_info(ast, 64, 1, FLIC_TFTD_SAMPLE_RATE); 00172 } else if (AV_RL16(&header[0x10]) == FLIC_CHUNK_MAGIC_1) { 00173 av_set_pts_info(st, 64, FLIC_MC_SPEED, 70); 00174 00175 /* rewind the stream since the first chunk is at offset 12 */ 00176 avio_seek(pb, 12, SEEK_SET); 00177 00178 /* send over abbreviated FLIC header chunk */ 00179 av_free(st->codec->extradata); 00180 st->codec->extradata_size = 12; 00181 st->codec->extradata = av_malloc(12); 00182 memcpy(st->codec->extradata, header, 12); 00183 00184 } else if (magic_number == FLIC_FILE_MAGIC_1) { 00185 av_set_pts_info(st, 64, speed, 70); 00186 } else if ((magic_number == FLIC_FILE_MAGIC_2) || 00187 (magic_number == FLIC_FILE_MAGIC_3)) { 00188 av_set_pts_info(st, 64, speed, 1000); 00189 } else { 00190 av_log(s, AV_LOG_INFO, "Invalid or unsupported magic chunk in file\n"); 00191 return AVERROR_INVALIDDATA; 00192 } 00193 00194 return 0; 00195 } 00196 00197 static int flic_read_packet(AVFormatContext *s, 00198 AVPacket *pkt) 00199 { 00200 FlicDemuxContext *flic = s->priv_data; 00201 AVIOContext *pb = s->pb; 00202 int packet_read = 0; 00203 unsigned int size; 00204 int magic; 00205 int ret = 0; 00206 unsigned char preamble[FLIC_PREAMBLE_SIZE]; 00207 00208 while (!packet_read) { 00209 00210 if ((ret = avio_read(pb, preamble, FLIC_PREAMBLE_SIZE)) != 00211 FLIC_PREAMBLE_SIZE) { 00212 ret = AVERROR(EIO); 00213 break; 00214 } 00215 00216 size = AV_RL32(&preamble[0]); 00217 magic = AV_RL16(&preamble[4]); 00218 00219 if (((magic == FLIC_CHUNK_MAGIC_1) || (magic == FLIC_CHUNK_MAGIC_2)) && size > FLIC_PREAMBLE_SIZE) { 00220 if (av_new_packet(pkt, size)) { 00221 ret = AVERROR(EIO); 00222 break; 00223 } 00224 pkt->stream_index = flic->video_stream_index; 00225 pkt->pts = flic->frame_number++; 00226 pkt->pos = avio_tell(pb); 00227 memcpy(pkt->data, preamble, FLIC_PREAMBLE_SIZE); 00228 ret = avio_read(pb, pkt->data + FLIC_PREAMBLE_SIZE, 00229 size - FLIC_PREAMBLE_SIZE); 00230 if (ret != size - FLIC_PREAMBLE_SIZE) { 00231 av_free_packet(pkt); 00232 ret = AVERROR(EIO); 00233 } 00234 packet_read = 1; 00235 } else if (magic == FLIC_TFTD_CHUNK_AUDIO) { 00236 if (av_new_packet(pkt, size)) { 00237 ret = AVERROR(EIO); 00238 break; 00239 } 00240 00241 /* skip useless 10B sub-header (yes, it's not accounted for in the chunk header) */ 00242 avio_skip(pb, 10); 00243 00244 pkt->stream_index = flic->audio_stream_index; 00245 pkt->pos = avio_tell(pb); 00246 ret = avio_read(pb, pkt->data, size); 00247 00248 if (ret != size) { 00249 av_free_packet(pkt); 00250 ret = AVERROR(EIO); 00251 } 00252 00253 packet_read = 1; 00254 } else { 00255 /* not interested in this chunk */ 00256 avio_skip(pb, size - 6); 00257 } 00258 } 00259 00260 return ret; 00261 } 00262 00263 AVInputFormat ff_flic_demuxer = { 00264 "flic", 00265 NULL_IF_CONFIG_SMALL("FLI/FLC/FLX animation format"), 00266 sizeof(FlicDemuxContext), 00267 flic_probe, 00268 flic_read_header, 00269 flic_read_packet, 00270 };