00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00027 #include "libavutil/intreadwrite.h"
00028 #include "avformat.h"
00029
00030 typedef struct {
00031 int base_record;
00032 unsigned int nb_records;
00033 int size;
00034 } Page;
00035
00036 typedef struct {
00037 unsigned int nb_pages;
00038 unsigned int nb_records;
00039 int page_table_offset;
00040 #define MAX_PAGES 256
00041 Page pt[MAX_PAGES];
00042 int page;
00043 int record;
00044 } AnmDemuxContext;
00045
00046 #define LPF_TAG MKTAG('L','P','F',' ')
00047 #define ANIM_TAG MKTAG('A','N','I','M')
00048
00049 static int probe(AVProbeData *p)
00050 {
00051
00052 if (AV_RL32(&p->buf[0]) == LPF_TAG &&
00053 AV_RL32(&p->buf[16]) == ANIM_TAG &&
00054 AV_RL16(&p->buf[20]) && AV_RL16(&p->buf[22]))
00055 return AVPROBE_SCORE_MAX;
00056 return 0;
00057 }
00058
00062 static int find_record(const AnmDemuxContext *anm, int record)
00063 {
00064 int i;
00065
00066 if (record >= anm->nb_records)
00067 return AVERROR_EOF;
00068
00069 for (i = 0; i < MAX_PAGES; i++) {
00070 const Page *p = &anm->pt[i];
00071 if (p->nb_records > 0 && record >= p->base_record && record < p->base_record + p->nb_records)
00072 return i;
00073 }
00074
00075 return AVERROR_INVALIDDATA;
00076 }
00077
00078 static int read_header(AVFormatContext *s,
00079 AVFormatParameters *ap)
00080 {
00081 AnmDemuxContext *anm = s->priv_data;
00082 ByteIOContext *pb = s->pb;
00083 AVStream *st;
00084 int i, ret;
00085
00086 url_fskip(pb, 4);
00087 if (get_le16(pb) != MAX_PAGES) {
00088 av_log_ask_for_sample(s, "max_pages != " AV_STRINGIFY(MAX_PAGES) "\n");
00089 return AVERROR_INVALIDDATA;
00090 }
00091
00092 anm->nb_pages = get_le16(pb);
00093 anm->nb_records = get_le32(pb);
00094 url_fskip(pb, 2);
00095 anm->page_table_offset = get_le16(pb);
00096 if (get_le32(pb) != ANIM_TAG)
00097 return AVERROR_INVALIDDATA;
00098
00099
00100 st = av_new_stream(s, 0);
00101 if (!st)
00102 return AVERROR(ENOMEM);
00103 st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00104 st->codec->codec_id = CODEC_ID_ANM;
00105 st->codec->codec_tag = 0;
00106 st->codec->width = get_le16(pb);
00107 st->codec->height = get_le16(pb);
00108 if (get_byte(pb) != 0)
00109 goto invalid;
00110 url_fskip(pb, 1);
00111
00112
00113 if (get_byte(pb))
00114 anm->nb_records = FFMAX(anm->nb_records - 1, 0);
00115
00116 url_fskip(pb, 1);
00117
00118 if (get_byte(pb) != 0)
00119 goto invalid;
00120
00121 if (get_byte(pb) != 1)
00122 goto invalid;
00123
00124 url_fskip(pb, 1);
00125
00126 if (get_byte(pb) != 1)
00127 goto invalid;
00128
00129 url_fskip(pb, 32);
00130 st->nb_frames = get_le32(pb);
00131 av_set_pts_info(st, 64, 1, get_le16(pb));
00132 url_fskip(pb, 58);
00133
00134
00135 st->codec->extradata_size = 16*8 + 4*256;
00136 st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
00137 if (!st->codec->extradata) {
00138 ret = AVERROR(ENOMEM);
00139 goto close_and_return;
00140 }
00141 ret = get_buffer(pb, st->codec->extradata, st->codec->extradata_size);
00142 if (ret < 0)
00143 goto close_and_return;
00144
00145
00146 ret = url_fseek(pb, anm->page_table_offset, SEEK_SET);
00147 if (ret < 0)
00148 goto close_and_return;
00149
00150 for (i = 0; i < MAX_PAGES; i++) {
00151 Page *p = &anm->pt[i];
00152 p->base_record = get_le16(pb);
00153 p->nb_records = get_le16(pb);
00154 p->size = get_le16(pb);
00155 }
00156
00157
00158 anm->page = find_record(anm, 0);
00159 if (anm->page < 0) {
00160 ret = anm->page;
00161 goto close_and_return;
00162 }
00163
00164 anm->record = -1;
00165 return 0;
00166
00167 invalid:
00168 av_log_ask_for_sample(s, NULL);
00169 ret = AVERROR_INVALIDDATA;
00170
00171 close_and_return:
00172 av_close_input_stream(s);
00173 return ret;
00174 }
00175
00176 static int read_packet(AVFormatContext *s,
00177 AVPacket *pkt)
00178 {
00179 AnmDemuxContext *anm = s->priv_data;
00180 ByteIOContext *pb = s->pb;
00181 Page *p;
00182 int tmp, record_size;
00183
00184 if (url_feof(s->pb))
00185 return AVERROR(EIO);
00186
00187 if (anm->page < 0)
00188 return anm->page;
00189
00190 repeat:
00191 p = &anm->pt[anm->page];
00192
00193
00194 if (anm->record < 0) {
00195 url_fseek(pb, anm->page_table_offset + MAX_PAGES*6 + (anm->page<<16), SEEK_SET);
00196 url_fskip(pb, 8 + 2*p->nb_records);
00197 anm->record = 0;
00198 }
00199
00200
00201
00202 if (anm->record >= p->nb_records) {
00203 anm->page = find_record(anm, p->base_record + p->nb_records);
00204 if (anm->page < 0)
00205 return anm->page;
00206 anm->record = -1;
00207 goto repeat;
00208 }
00209
00210
00211 tmp = url_ftell(pb);
00212 url_fseek(pb, anm->page_table_offset + MAX_PAGES*6 + (anm->page<<16) +
00213 8 + anm->record * 2, SEEK_SET);
00214 record_size = get_le16(pb);
00215 url_fseek(pb, tmp, SEEK_SET);
00216
00217
00218 pkt->size = av_get_packet(s->pb, pkt, record_size);
00219 if (pkt->size < 0)
00220 return pkt->size;
00221 if (p->base_record + anm->record == 0)
00222 pkt->flags |= AV_PKT_FLAG_KEY;
00223
00224 anm->record++;
00225 return 0;
00226 }
00227
00228 AVInputFormat anm_demuxer = {
00229 "anm",
00230 NULL_IF_CONFIG_SMALL("Deluxe Paint Animation"),
00231 sizeof(AnmDemuxContext),
00232 probe,
00233 read_header,
00234 read_packet,
00235 };