00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
00041
00042 #define FLIC_CHUNK_MAGIC_1 0xF1FA
00043 #define FLIC_CHUNK_MAGIC_2 0xF5FA
00044 #define FLIC_MC_SPEED 5
00045 #define FLIC_DEFAULT_SPEED 5
00046 #define FLIC_TFTD_CHUNK_AUDIO 0xAAAA
00047
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
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
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;
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
00120
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
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
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
00141
00142
00143
00144
00145
00146 if (AV_RL16(&preamble[4]) == FLIC_TFTD_CHUNK_AUDIO) {
00147
00148 ast = av_new_stream(s, 1);
00149 if (!ast)
00150 return AVERROR(ENOMEM);
00151
00152 flic->audio_stream_index = ast->index;
00153
00154
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
00168
00169
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
00176 avio_seek(pb, 12, SEEK_SET);
00177
00178
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
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
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 };