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