Libav 0.7.1
|
00001 /* 00002 * Deluxe Paint Animation demuxer 00003 * Copyright (c) 2009 Peter Ross 00004 * 00005 * This file is part of Libav. 00006 * 00007 * Libav is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * Libav is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with Libav; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 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 /* verify tags and video dimensions */ 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 AVIOContext *pb = s->pb; 00083 AVStream *st; 00084 int i, ret; 00085 00086 avio_skip(pb, 4); /* magic number */ 00087 if (avio_rl16(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 = avio_rl16(pb); 00093 anm->nb_records = avio_rl32(pb); 00094 avio_skip(pb, 2); /* max records per page */ 00095 anm->page_table_offset = avio_rl16(pb); 00096 if (avio_rl32(pb) != ANIM_TAG) 00097 return AVERROR_INVALIDDATA; 00098 00099 /* video stream */ 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; /* no fourcc */ 00106 st->codec->width = avio_rl16(pb); 00107 st->codec->height = avio_rl16(pb); 00108 if (avio_r8(pb) != 0) 00109 goto invalid; 00110 avio_skip(pb, 1); /* frame rate multiplier info */ 00111 00112 /* ignore last delta record (used for looping) */ 00113 if (avio_r8(pb)) /* has_last_delta */ 00114 anm->nb_records = FFMAX(anm->nb_records - 1, 0); 00115 00116 avio_skip(pb, 1); /* last_delta_valid */ 00117 00118 if (avio_r8(pb) != 0) 00119 goto invalid; 00120 00121 if (avio_r8(pb) != 1) 00122 goto invalid; 00123 00124 avio_skip(pb, 1); /* other recs per frame */ 00125 00126 if (avio_r8(pb) != 1) 00127 goto invalid; 00128 00129 avio_skip(pb, 32); /* record_types */ 00130 st->nb_frames = avio_rl32(pb); 00131 av_set_pts_info(st, 64, 1, avio_rl16(pb)); 00132 avio_skip(pb, 58); 00133 00134 /* color cycling and palette data */ 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 = avio_read(pb, st->codec->extradata, st->codec->extradata_size); 00142 if (ret < 0) 00143 goto close_and_return; 00144 00145 /* read page table */ 00146 ret = avio_seek(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 = avio_rl16(pb); 00153 p->nb_records = avio_rl16(pb); 00154 p->size = avio_rl16(pb); 00155 } 00156 00157 /* find page of first frame */ 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 AVIOContext *pb = s->pb; 00181 Page *p; 00182 int tmp, record_size; 00183 00184 if (s->pb->eof_reached) 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 /* parse page header */ 00194 if (anm->record < 0) { 00195 avio_seek(pb, anm->page_table_offset + MAX_PAGES*6 + (anm->page<<16), SEEK_SET); 00196 avio_skip(pb, 8 + 2*p->nb_records); 00197 anm->record = 0; 00198 } 00199 00200 /* if we have fetched all records in this page, then find the 00201 next page and repeat */ 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 /* fetch record size */ 00211 tmp = avio_tell(pb); 00212 avio_seek(pb, anm->page_table_offset + MAX_PAGES*6 + (anm->page<<16) + 00213 8 + anm->record * 2, SEEK_SET); 00214 record_size = avio_rl16(pb); 00215 avio_seek(pb, tmp, SEEK_SET); 00216 00217 /* fetch record */ 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 ff_anm_demuxer = { 00229 "anm", 00230 NULL_IF_CONFIG_SMALL("Deluxe Paint Animation"), 00231 sizeof(AnmDemuxContext), 00232 probe, 00233 read_header, 00234 read_packet, 00235 };