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 "avformat.h"
00036
00037 #define FLIC_FILE_MAGIC_1 0xAF11
00038 #define FLIC_FILE_MAGIC_2 0xAF12
00039 #define FLIC_FILE_MAGIC_3 0xAF44
00040
00041 #define FLIC_CHUNK_MAGIC_1 0xF1FA
00042 #define FLIC_CHUNK_MAGIC_2 0xF5FA
00043 #define FLIC_MC_SPEED 5
00044 #define FLIC_DEFAULT_SPEED 5
00045 #define FLIC_TFTD_CHUNK_AUDIO 0xAAAA
00046
00047 #define FLIC_TFTD_SAMPLE_RATE 22050
00048
00049 #define FLIC_HEADER_SIZE 128
00050 #define FLIC_PREAMBLE_SIZE 6
00051
00052 typedef struct FlicDemuxContext {
00053 int video_stream_index;
00054 int audio_stream_index;
00055 int frame_number;
00056 } FlicDemuxContext;
00057
00058 static int flic_probe(AVProbeData *p)
00059 {
00060 int magic_number;
00061
00062 if(p->buf_size < FLIC_HEADER_SIZE)
00063 return 0;
00064
00065 magic_number = AV_RL16(&p->buf[4]);
00066 if ((magic_number != FLIC_FILE_MAGIC_1) &&
00067 (magic_number != FLIC_FILE_MAGIC_2) &&
00068 (magic_number != FLIC_FILE_MAGIC_3))
00069 return 0;
00070
00071 if(AV_RL16(&p->buf[0x10]) != FLIC_CHUNK_MAGIC_1){
00072 if(AV_RL32(&p->buf[0x10]) > 2000)
00073 return 0;
00074 }
00075
00076 if( AV_RL16(&p->buf[0x08]) > 4096
00077 || AV_RL16(&p->buf[0x0A]) > 4096)
00078 return 0;
00079
00080
00081 return AVPROBE_SCORE_MAX;
00082 }
00083
00084 static int flic_read_header(AVFormatContext *s,
00085 AVFormatParameters *ap)
00086 {
00087 FlicDemuxContext *flic = s->priv_data;
00088 ByteIOContext *pb = s->pb;
00089 unsigned char header[FLIC_HEADER_SIZE];
00090 AVStream *st, *ast;
00091 int speed;
00092 int magic_number;
00093 unsigned char preamble[FLIC_PREAMBLE_SIZE];
00094
00095 flic->frame_number = 0;
00096
00097
00098 if (get_buffer(pb, header, FLIC_HEADER_SIZE) != FLIC_HEADER_SIZE)
00099 return AVERROR(EIO);
00100
00101 magic_number = AV_RL16(&header[4]);
00102 speed = AV_RL32(&header[0x10]);
00103 if (speed == 0)
00104 speed = FLIC_DEFAULT_SPEED;
00105
00106
00107 st = av_new_stream(s, 0);
00108 if (!st)
00109 return AVERROR(ENOMEM);
00110 flic->video_stream_index = st->index;
00111 st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00112 st->codec->codec_id = CODEC_ID_FLIC;
00113 st->codec->codec_tag = 0;
00114 st->codec->width = AV_RL16(&header[0x08]);
00115 st->codec->height = AV_RL16(&header[0x0A]);
00116
00117 if (!st->codec->width || !st->codec->height) {
00118
00119
00120 av_log(s, AV_LOG_WARNING,
00121 "File with no specified width/height. Trying 640x480.\n");
00122 st->codec->width = 640;
00123 st->codec->height = 480;
00124 }
00125
00126
00127 st->codec->extradata_size = FLIC_HEADER_SIZE;
00128 st->codec->extradata = av_malloc(FLIC_HEADER_SIZE);
00129 memcpy(st->codec->extradata, header, FLIC_HEADER_SIZE);
00130
00131
00132 if (get_buffer(pb, preamble, FLIC_PREAMBLE_SIZE) != FLIC_PREAMBLE_SIZE) {
00133 av_log(s, AV_LOG_ERROR, "Failed to peek at preamble\n");
00134 return AVERROR(EIO);
00135 }
00136
00137 url_fseek(pb, -FLIC_PREAMBLE_SIZE, SEEK_CUR);
00138
00139
00140
00141
00142
00143
00144
00145 if (AV_RL16(&preamble[4]) == FLIC_TFTD_CHUNK_AUDIO) {
00146
00147 ast = av_new_stream(s, 1);
00148 if (!ast)
00149 return AVERROR(ENOMEM);
00150
00151 flic->audio_stream_index = ast->index;
00152
00153
00154 ast->codec->block_align = AV_RL32(&preamble[0]);
00155 ast->codec->codec_type = CODEC_TYPE_AUDIO;
00156 ast->codec->codec_id = CODEC_ID_PCM_U8;
00157 ast->codec->codec_tag = 0;
00158 ast->codec->sample_rate = FLIC_TFTD_SAMPLE_RATE;
00159 ast->codec->channels = 1;
00160 ast->codec->sample_fmt = SAMPLE_FMT_U8;
00161 ast->codec->bit_rate = st->codec->sample_rate * 8;
00162 ast->codec->bits_per_coded_sample = 8;
00163 ast->codec->channel_layout = CH_LAYOUT_MONO;
00164 ast->codec->extradata_size = 0;
00165
00166
00167
00168
00169 av_set_pts_info(st, 64, ast->codec->block_align, FLIC_TFTD_SAMPLE_RATE);
00170 av_set_pts_info(ast, 64, 1, FLIC_TFTD_SAMPLE_RATE);
00171 } else if (AV_RL16(&header[0x10]) == FLIC_CHUNK_MAGIC_1) {
00172 av_set_pts_info(st, 64, FLIC_MC_SPEED, 70);
00173
00174
00175 url_fseek(pb, 12, SEEK_SET);
00176
00177
00178 av_free(st->codec->extradata);
00179 st->codec->extradata_size = 12;
00180 st->codec->extradata = av_malloc(12);
00181 memcpy(st->codec->extradata, header, 12);
00182
00183 } else if (magic_number == FLIC_FILE_MAGIC_1) {
00184 av_set_pts_info(st, 64, speed, 70);
00185 } else if ((magic_number == FLIC_FILE_MAGIC_2) ||
00186 (magic_number == FLIC_FILE_MAGIC_3)) {
00187 av_set_pts_info(st, 64, speed, 1000);
00188 } else {
00189 av_log(s, AV_LOG_INFO, "Invalid or unsupported magic chunk in file\n");
00190 return AVERROR_INVALIDDATA;
00191 }
00192
00193 return 0;
00194 }
00195
00196 static int flic_read_packet(AVFormatContext *s,
00197 AVPacket *pkt)
00198 {
00199 FlicDemuxContext *flic = s->priv_data;
00200 ByteIOContext *pb = s->pb;
00201 int packet_read = 0;
00202 unsigned int size;
00203 int magic;
00204 int ret = 0;
00205 unsigned char preamble[FLIC_PREAMBLE_SIZE];
00206
00207 while (!packet_read) {
00208
00209 if ((ret = get_buffer(pb, preamble, FLIC_PREAMBLE_SIZE)) !=
00210 FLIC_PREAMBLE_SIZE) {
00211 ret = AVERROR(EIO);
00212 break;
00213 }
00214
00215 size = AV_RL32(&preamble[0]);
00216 magic = AV_RL16(&preamble[4]);
00217
00218 if (((magic == FLIC_CHUNK_MAGIC_1) || (magic == FLIC_CHUNK_MAGIC_2)) && size > FLIC_PREAMBLE_SIZE) {
00219 if (av_new_packet(pkt, size)) {
00220 ret = AVERROR(EIO);
00221 break;
00222 }
00223 pkt->stream_index = flic->video_stream_index;
00224 pkt->pts = flic->frame_number++;
00225 pkt->pos = url_ftell(pb);
00226 memcpy(pkt->data, preamble, FLIC_PREAMBLE_SIZE);
00227 ret = get_buffer(pb, pkt->data + FLIC_PREAMBLE_SIZE,
00228 size - FLIC_PREAMBLE_SIZE);
00229 if (ret != size - FLIC_PREAMBLE_SIZE) {
00230 av_free_packet(pkt);
00231 ret = AVERROR(EIO);
00232 }
00233 packet_read = 1;
00234 } else if (magic == FLIC_TFTD_CHUNK_AUDIO) {
00235 if (av_new_packet(pkt, size)) {
00236 ret = AVERROR(EIO);
00237 break;
00238 }
00239
00240
00241 url_fseek(pb, 10, SEEK_CUR);
00242
00243 pkt->stream_index = flic->audio_stream_index;
00244 pkt->pos = url_ftell(pb);
00245 ret = get_buffer(pb, pkt->data, size);
00246
00247 if (ret != size) {
00248 av_free_packet(pkt);
00249 ret = AVERROR(EIO);
00250 }
00251
00252 packet_read = 1;
00253 } else {
00254
00255 url_fseek(pb, size - 6, SEEK_CUR);
00256 }
00257 }
00258
00259 return ret;
00260 }
00261
00262 AVInputFormat flic_demuxer = {
00263 "flic",
00264 NULL_IF_CONFIG_SMALL("FLI/FLC/FLX animation format"),
00265 sizeof(FlicDemuxContext),
00266 flic_probe,
00267 flic_read_header,
00268 flic_read_packet,
00269 };