00001 /* 00002 * FLI/FLC Animation File Demuxer 00003 * Copyright (c) 2003 The ffmpeg Project 00004 * 00005 * This file is part of FFmpeg. 00006 * 00007 * FFmpeg 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 * FFmpeg 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 FFmpeg; 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 "avformat.h" 00036 00037 #define FLIC_FILE_MAGIC_1 0xAF11 00038 #define FLIC_FILE_MAGIC_2 0xAF12 00039 #define FLIC_FILE_MAGIC_3 0xAF44 /* Flic Type for Extended FLX Format which 00040 originated in Dave's Targa Animator (DTA) */ 00041 #define FLIC_CHUNK_MAGIC_1 0xF1FA 00042 #define FLIC_CHUNK_MAGIC_2 0xF5FA 00043 #define FLIC_MC_SPEED 5 /* speed for Magic Carpet game FLIs */ 00044 #define FLIC_DEFAULT_SPEED 5 /* for FLIs that have 0 speed */ 00045 00046 #define FLIC_HEADER_SIZE 128 00047 #define FLIC_PREAMBLE_SIZE 6 00048 00049 typedef struct FlicDemuxContext { 00050 int video_stream_index; 00051 int frame_number; 00052 } FlicDemuxContext; 00053 00054 static int flic_probe(AVProbeData *p) 00055 { 00056 int magic_number; 00057 00058 if(p->buf_size < FLIC_HEADER_SIZE) 00059 return 0; 00060 00061 magic_number = AV_RL16(&p->buf[4]); 00062 if ((magic_number != FLIC_FILE_MAGIC_1) && 00063 (magic_number != FLIC_FILE_MAGIC_2) && 00064 (magic_number != FLIC_FILE_MAGIC_3)) 00065 return 0; 00066 00067 if(AV_RL16(&p->buf[0x10]) != FLIC_CHUNK_MAGIC_1){ 00068 if(AV_RL32(&p->buf[0x10]) > 2000) 00069 return 0; 00070 } 00071 00072 if( AV_RL16(&p->buf[0x08]) > 4096 00073 || AV_RL16(&p->buf[0x0A]) > 4096) 00074 return 0; 00075 00076 00077 return AVPROBE_SCORE_MAX; 00078 } 00079 00080 static int flic_read_header(AVFormatContext *s, 00081 AVFormatParameters *ap) 00082 { 00083 FlicDemuxContext *flic = s->priv_data; 00084 ByteIOContext *pb = s->pb; 00085 unsigned char header[FLIC_HEADER_SIZE]; 00086 AVStream *st; 00087 int speed; 00088 int magic_number; 00089 00090 flic->frame_number = 0; 00091 00092 /* load the whole header and pull out the width and height */ 00093 if (get_buffer(pb, header, FLIC_HEADER_SIZE) != FLIC_HEADER_SIZE) 00094 return AVERROR(EIO); 00095 00096 magic_number = AV_RL16(&header[4]); 00097 speed = AV_RL32(&header[0x10]); 00098 if (speed == 0) 00099 speed = FLIC_DEFAULT_SPEED; 00100 00101 /* initialize the decoder streams */ 00102 st = av_new_stream(s, 0); 00103 if (!st) 00104 return AVERROR(ENOMEM); 00105 flic->video_stream_index = st->index; 00106 st->codec->codec_type = CODEC_TYPE_VIDEO; 00107 st->codec->codec_id = CODEC_ID_FLIC; 00108 st->codec->codec_tag = 0; /* no fourcc */ 00109 st->codec->width = AV_RL16(&header[0x08]); 00110 st->codec->height = AV_RL16(&header[0x0A]); 00111 00112 if (!st->codec->width || !st->codec->height) { 00113 /* Ugly hack needed for the following sample: */ 00114 /* http://samples.mplayerhq.hu/fli-flc/fli-bugs/specular.flc */ 00115 av_log(s, AV_LOG_WARNING, 00116 "File with no specified width/height. Trying 640x480.\n"); 00117 st->codec->width = 640; 00118 st->codec->height = 480; 00119 } 00120 00121 /* send over the whole 128-byte FLIC header */ 00122 st->codec->extradata_size = FLIC_HEADER_SIZE; 00123 st->codec->extradata = av_malloc(FLIC_HEADER_SIZE); 00124 memcpy(st->codec->extradata, header, FLIC_HEADER_SIZE); 00125 00126 /* Time to figure out the framerate: If there is a FLIC chunk magic 00127 * number at offset 0x10, assume this is from the Bullfrog game, 00128 * Magic Carpet. */ 00129 if (AV_RL16(&header[0x10]) == FLIC_CHUNK_MAGIC_1) { 00130 00131 av_set_pts_info(st, 64, FLIC_MC_SPEED, 70); 00132 00133 /* rewind the stream since the first chunk is at offset 12 */ 00134 url_fseek(pb, 12, SEEK_SET); 00135 00136 /* send over abbreviated FLIC header chunk */ 00137 av_free(st->codec->extradata); 00138 st->codec->extradata_size = 12; 00139 st->codec->extradata = av_malloc(12); 00140 memcpy(st->codec->extradata, header, 12); 00141 00142 } else if (magic_number == FLIC_FILE_MAGIC_1) { 00143 av_set_pts_info(st, 64, speed, 70); 00144 } else if ((magic_number == FLIC_FILE_MAGIC_2) || 00145 (magic_number == FLIC_FILE_MAGIC_3)) { 00146 av_set_pts_info(st, 64, speed, 1000); 00147 } else { 00148 av_log(s, AV_LOG_INFO, "Invalid or unsupported magic chunk in file\n"); 00149 return AVERROR_INVALIDDATA; 00150 } 00151 00152 return 0; 00153 } 00154 00155 static int flic_read_packet(AVFormatContext *s, 00156 AVPacket *pkt) 00157 { 00158 FlicDemuxContext *flic = s->priv_data; 00159 ByteIOContext *pb = s->pb; 00160 int packet_read = 0; 00161 unsigned int size; 00162 int magic; 00163 int ret = 0; 00164 unsigned char preamble[FLIC_PREAMBLE_SIZE]; 00165 00166 while (!packet_read) { 00167 00168 if ((ret = get_buffer(pb, preamble, FLIC_PREAMBLE_SIZE)) != 00169 FLIC_PREAMBLE_SIZE) { 00170 ret = AVERROR(EIO); 00171 break; 00172 } 00173 00174 size = AV_RL32(&preamble[0]); 00175 magic = AV_RL16(&preamble[4]); 00176 00177 if (((magic == FLIC_CHUNK_MAGIC_1) || (magic == FLIC_CHUNK_MAGIC_2)) && size > FLIC_PREAMBLE_SIZE) { 00178 if (av_new_packet(pkt, size)) { 00179 ret = AVERROR(EIO); 00180 break; 00181 } 00182 pkt->stream_index = flic->video_stream_index; 00183 pkt->pts = flic->frame_number++; 00184 pkt->pos = url_ftell(pb); 00185 memcpy(pkt->data, preamble, FLIC_PREAMBLE_SIZE); 00186 ret = get_buffer(pb, pkt->data + FLIC_PREAMBLE_SIZE, 00187 size - FLIC_PREAMBLE_SIZE); 00188 if (ret != size - FLIC_PREAMBLE_SIZE) { 00189 av_free_packet(pkt); 00190 ret = AVERROR(EIO); 00191 } 00192 packet_read = 1; 00193 } else { 00194 /* not interested in this chunk */ 00195 url_fseek(pb, size - 6, SEEK_CUR); 00196 } 00197 } 00198 00199 return ret; 00200 } 00201 00202 AVInputFormat flic_demuxer = { 00203 "flic", 00204 NULL_IF_CONFIG_SMALL("FLI/FLC/FLX animation format"), 00205 sizeof(FlicDemuxContext), 00206 flic_probe, 00207 flic_read_header, 00208 flic_read_packet, 00209 };