00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00034 #include "avformat.h"
00035
00036 #define FLIC_FILE_MAGIC_1 0xAF11
00037 #define FLIC_FILE_MAGIC_2 0xAF12
00038 #define FLIC_FILE_MAGIC_3 0xAF44
00039
00040 #define FLIC_CHUNK_MAGIC_1 0xF1FA
00041 #define FLIC_CHUNK_MAGIC_2 0xF5FA
00042 #define FLIC_MC_SPEED 5
00043 #define FLIC_DEFAULT_SPEED 5
00044
00045 #define FLIC_HEADER_SIZE 128
00046 #define FLIC_PREAMBLE_SIZE 6
00047
00048 typedef struct FlicDemuxContext {
00049 int video_stream_index;
00050 int frame_number;
00051 } FlicDemuxContext;
00052
00053 static int flic_probe(AVProbeData *p)
00054 {
00055 int magic_number;
00056
00057 magic_number = AV_RL16(&p->buf[4]);
00058 if ((magic_number != FLIC_FILE_MAGIC_1) &&
00059 (magic_number != FLIC_FILE_MAGIC_2) &&
00060 (magic_number != FLIC_FILE_MAGIC_3))
00061 return 0;
00062
00063 return AVPROBE_SCORE_MAX;
00064 }
00065
00066 static int flic_read_header(AVFormatContext *s,
00067 AVFormatParameters *ap)
00068 {
00069 FlicDemuxContext *flic = s->priv_data;
00070 ByteIOContext *pb = s->pb;
00071 unsigned char header[FLIC_HEADER_SIZE];
00072 AVStream *st;
00073 int speed;
00074 int magic_number;
00075
00076 flic->frame_number = 0;
00077
00078
00079 if (get_buffer(pb, header, FLIC_HEADER_SIZE) != FLIC_HEADER_SIZE)
00080 return AVERROR(EIO);
00081
00082 magic_number = AV_RL16(&header[4]);
00083 speed = AV_RL32(&header[0x10]);
00084 if (speed == 0)
00085 speed = FLIC_DEFAULT_SPEED;
00086
00087
00088 st = av_new_stream(s, 0);
00089 if (!st)
00090 return AVERROR(ENOMEM);
00091 flic->video_stream_index = st->index;
00092 st->codec->codec_type = CODEC_TYPE_VIDEO;
00093 st->codec->codec_id = CODEC_ID_FLIC;
00094 st->codec->codec_tag = 0;
00095 st->codec->width = AV_RL16(&header[0x08]);
00096 st->codec->height = AV_RL16(&header[0x0A]);
00097
00098 if (!st->codec->width || !st->codec->height) {
00099
00100
00101 av_log(s, AV_LOG_WARNING,
00102 "File with no specified width/height. Trying 640x480.\n");
00103 st->codec->width = 640;
00104 st->codec->height = 480;
00105 }
00106
00107
00108 st->codec->extradata_size = FLIC_HEADER_SIZE;
00109 st->codec->extradata = av_malloc(FLIC_HEADER_SIZE);
00110 memcpy(st->codec->extradata, header, FLIC_HEADER_SIZE);
00111
00112
00113
00114
00115 if (AV_RL16(&header[0x10]) == FLIC_CHUNK_MAGIC_1) {
00116
00117 av_set_pts_info(st, 64, FLIC_MC_SPEED, 70);
00118
00119
00120 url_fseek(pb, 12, SEEK_SET);
00121
00122
00123 av_free(st->codec->extradata);
00124 st->codec->extradata_size = 12;
00125 st->codec->extradata = av_malloc(12);
00126 memcpy(st->codec->extradata, header, 12);
00127
00128 } else if (magic_number == FLIC_FILE_MAGIC_1) {
00129 av_set_pts_info(st, 64, speed, 70);
00130 } else if ((magic_number == FLIC_FILE_MAGIC_2) ||
00131 (magic_number == FLIC_FILE_MAGIC_3)) {
00132 av_set_pts_info(st, 64, speed, 1000);
00133 } else {
00134 av_log(s, AV_LOG_INFO, "Invalid or unsupported magic chunk in file\n");
00135 return AVERROR_INVALIDDATA;
00136 }
00137
00138 return 0;
00139 }
00140
00141 static int flic_read_packet(AVFormatContext *s,
00142 AVPacket *pkt)
00143 {
00144 FlicDemuxContext *flic = s->priv_data;
00145 ByteIOContext *pb = s->pb;
00146 int packet_read = 0;
00147 unsigned int size;
00148 int magic;
00149 int ret = 0;
00150 unsigned char preamble[FLIC_PREAMBLE_SIZE];
00151
00152 while (!packet_read) {
00153
00154 if ((ret = get_buffer(pb, preamble, FLIC_PREAMBLE_SIZE)) !=
00155 FLIC_PREAMBLE_SIZE) {
00156 ret = AVERROR(EIO);
00157 break;
00158 }
00159
00160 size = AV_RL32(&preamble[0]);
00161 magic = AV_RL16(&preamble[4]);
00162
00163 if (((magic == FLIC_CHUNK_MAGIC_1) || (magic == FLIC_CHUNK_MAGIC_2)) && size > FLIC_PREAMBLE_SIZE) {
00164 if (av_new_packet(pkt, size)) {
00165 ret = AVERROR(EIO);
00166 break;
00167 }
00168 pkt->stream_index = flic->video_stream_index;
00169 pkt->pts = flic->frame_number++;
00170 pkt->pos = url_ftell(pb);
00171 memcpy(pkt->data, preamble, FLIC_PREAMBLE_SIZE);
00172 ret = get_buffer(pb, pkt->data + FLIC_PREAMBLE_SIZE,
00173 size - FLIC_PREAMBLE_SIZE);
00174 if (ret != size - FLIC_PREAMBLE_SIZE) {
00175 av_free_packet(pkt);
00176 ret = AVERROR(EIO);
00177 }
00178 packet_read = 1;
00179 } else {
00180
00181 url_fseek(pb, size - 6, SEEK_CUR);
00182 }
00183 }
00184
00185 return ret;
00186 }
00187
00188 static int flic_read_close(AVFormatContext *s)
00189 {
00190
00191
00192 return 0;
00193 }
00194
00195 AVInputFormat flic_demuxer = {
00196 "flic",
00197 "FLI/FLC/FLX animation format",
00198 sizeof(FlicDemuxContext),
00199 flic_probe,
00200 flic_read_header,
00201 flic_read_packet,
00202 flic_read_close,
00203 };