ffmpeg / libavformat / anm.c @ 45a8a02a
History | View | Annotate | Download (6.36 KB)
1 | e6565055 | Peter Ross | /*
|
---|---|---|---|
2 | * Deluxe Paint Animation demuxer
|
||
3 | * Copyright (c) 2009 Peter Ross
|
||
4 | *
|
||
5 | * This file is part of FFmpeg.
|
||
6 | *
|
||
7 | * FFmpeg is free software; you can redistribute it and/or
|
||
8 | * modify it under the terms of the GNU Lesser General Public
|
||
9 | * License as published by the Free Software Foundation; either
|
||
10 | * version 2.1 of the License, or (at your option) any later version.
|
||
11 | *
|
||
12 | * FFmpeg is distributed in the hope that it will be useful,
|
||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
15 | * Lesser General Public License for more details.
|
||
16 | *
|
||
17 | * You should have received a copy of the GNU Lesser General Public
|
||
18 | * License along with FFmpeg; if not, write to the Free Software
|
||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
20 | */
|
||
21 | |||
22 | /**
|
||
23 | ba87f080 | Diego Biurrun | * @file
|
24 | e6565055 | Peter Ross | * Deluxe Paint Animation demuxer
|
25 | */
|
||
26 | |||
27 | #include "libavutil/intreadwrite.h" |
||
28 | #include "avformat.h" |
||
29 | |||
30 | typedef struct { |
||
31 | int base_record;
|
||
32 | unsigned int nb_records; |
||
33 | int size;
|
||
34 | } Page; |
||
35 | |||
36 | typedef struct { |
||
37 | a20df858 | Michael Niedermayer | unsigned int nb_pages; /**< total pages in file */ |
38 | unsigned int nb_records; /**< total records in file */ |
||
39 | e6565055 | Peter Ross | int page_table_offset;
|
40 | a20df858 | Michael Niedermayer | #define MAX_PAGES 256 /**< Deluxe Paint hardcoded value */ |
41 | Page pt[MAX_PAGES]; /**< page table */
|
||
42 | int page; /**< current page (or AVERROR_xxx code) */ |
||
43 | int record; /**< current record (with in page) */ |
||
44 | e6565055 | Peter Ross | } AnmDemuxContext; |
45 | |||
46 | #define LPF_TAG MKTAG('L','P','F',' ') |
||
47 | #define ANIM_TAG MKTAG('A','N','I','M') |
||
48 | |||
49 | static int probe(AVProbeData *p) |
||
50 | { |
||
51 | /* verify tags and video dimensions */
|
||
52 | if (AV_RL32(&p->buf[0]) == LPF_TAG && |
||
53 | AV_RL32(&p->buf[16]) == ANIM_TAG &&
|
||
54 | AV_RL16(&p->buf[20]) && AV_RL16(&p->buf[22])) |
||
55 | return AVPROBE_SCORE_MAX;
|
||
56 | return 0; |
||
57 | } |
||
58 | |||
59 | /**
|
||
60 | * @return page containing the requested record or AVERROR_XXX
|
||
61 | */
|
||
62 | static int find_record(const AnmDemuxContext *anm, int record) |
||
63 | { |
||
64 | int i;
|
||
65 | |||
66 | if (record >= anm->nb_records)
|
||
67 | return AVERROR_EOF;
|
||
68 | |||
69 | for (i = 0; i < MAX_PAGES; i++) { |
||
70 | const Page *p = &anm->pt[i];
|
||
71 | if (p->nb_records > 0 && record >= p->base_record && record < p->base_record + p->nb_records) |
||
72 | return i;
|
||
73 | } |
||
74 | |||
75 | return AVERROR_INVALIDDATA;
|
||
76 | } |
||
77 | |||
78 | static int read_header(AVFormatContext *s, |
||
79 | AVFormatParameters *ap) |
||
80 | { |
||
81 | AnmDemuxContext *anm = s->priv_data; |
||
82 | ae628ec1 | Anton Khirnov | AVIOContext *pb = s->pb; |
83 | e6565055 | Peter Ross | AVStream *st; |
84 | int i, ret;
|
||
85 | |||
86 | 45a8a02a | Anton Khirnov | avio_skip(pb, 4); /* magic number */ |
87 | b7effd4e | Anton Khirnov | if (avio_rl16(pb) != MAX_PAGES) {
|
88 | e6565055 | Peter Ross | av_log_ask_for_sample(s, "max_pages != " AV_STRINGIFY(MAX_PAGES) "\n"); |
89 | return AVERROR_INVALIDDATA;
|
||
90 | } |
||
91 | |||
92 | b7effd4e | Anton Khirnov | anm->nb_pages = avio_rl16(pb); |
93 | anm->nb_records = avio_rl32(pb); |
||
94 | 45a8a02a | Anton Khirnov | avio_skip(pb, 2); /* max records per page */ |
95 | b7effd4e | Anton Khirnov | anm->page_table_offset = avio_rl16(pb); |
96 | if (avio_rl32(pb) != ANIM_TAG)
|
||
97 | e6565055 | Peter Ross | return AVERROR_INVALIDDATA;
|
98 | |||
99 | /* video stream */
|
||
100 | st = av_new_stream(s, 0);
|
||
101 | if (!st)
|
||
102 | return AVERROR(ENOMEM);
|
||
103 | 72415b2a | Stefano Sabatini | st->codec->codec_type = AVMEDIA_TYPE_VIDEO; |
104 | e6565055 | Peter Ross | st->codec->codec_id = CODEC_ID_ANM; |
105 | st->codec->codec_tag = 0; /* no fourcc */ |
||
106 | b7effd4e | Anton Khirnov | st->codec->width = avio_rl16(pb); |
107 | st->codec->height = avio_rl16(pb); |
||
108 | if (avio_r8(pb) != 0) |
||
109 | e6565055 | Peter Ross | goto invalid;
|
110 | 45a8a02a | Anton Khirnov | avio_skip(pb, 1); /* frame rate multiplier info */ |
111 | e6565055 | Peter Ross | |
112 | /* ignore last delta record (used for looping) */
|
||
113 | b7effd4e | Anton Khirnov | if (avio_r8(pb)) /* has_last_delta */ |
114 | e6565055 | Peter Ross | anm->nb_records = FFMAX(anm->nb_records - 1, 0); |
115 | |||
116 | 45a8a02a | Anton Khirnov | avio_skip(pb, 1); /* last_delta_valid */ |
117 | e6565055 | Peter Ross | |
118 | b7effd4e | Anton Khirnov | if (avio_r8(pb) != 0) |
119 | e6565055 | Peter Ross | goto invalid;
|
120 | |||
121 | b7effd4e | Anton Khirnov | if (avio_r8(pb) != 1) |
122 | e6565055 | Peter Ross | goto invalid;
|
123 | |||
124 | 45a8a02a | Anton Khirnov | avio_skip(pb, 1); /* other recs per frame */ |
125 | e6565055 | Peter Ross | |
126 | b7effd4e | Anton Khirnov | if (avio_r8(pb) != 1) |
127 | e6565055 | Peter Ross | goto invalid;
|
128 | |||
129 | 45a8a02a | Anton Khirnov | avio_skip(pb, 32); /* record_types */ |
130 | b7effd4e | Anton Khirnov | st->nb_frames = avio_rl32(pb); |
131 | av_set_pts_info(st, 64, 1, avio_rl16(pb)); |
||
132 | 45a8a02a | Anton Khirnov | avio_skip(pb, 58);
|
133 | e6565055 | Peter Ross | |
134 | /* color cycling and palette data */
|
||
135 | st->codec->extradata_size = 16*8 + 4*256; |
||
136 | st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); |
||
137 | if (!st->codec->extradata) {
|
||
138 | ret = AVERROR(ENOMEM); |
||
139 | goto close_and_return;
|
||
140 | } |
||
141 | b7effd4e | Anton Khirnov | ret = avio_read(pb, st->codec->extradata, st->codec->extradata_size); |
142 | e6565055 | Peter Ross | if (ret < 0) |
143 | goto close_and_return;
|
||
144 | |||
145 | /* read page table */
|
||
146 | 6b4aa5da | Anton Khirnov | ret = avio_seek(pb, anm->page_table_offset, SEEK_SET); |
147 | e6565055 | Peter Ross | if (ret < 0) |
148 | goto close_and_return;
|
||
149 | |||
150 | for (i = 0; i < MAX_PAGES; i++) { |
||
151 | Page *p = &anm->pt[i]; |
||
152 | b7effd4e | Anton Khirnov | p->base_record = avio_rl16(pb); |
153 | p->nb_records = avio_rl16(pb); |
||
154 | p->size = avio_rl16(pb); |
||
155 | e6565055 | Peter Ross | } |
156 | |||
157 | /* find page of first frame */
|
||
158 | anm->page = find_record(anm, 0);
|
||
159 | if (anm->page < 0) { |
||
160 | ret = anm->page; |
||
161 | goto close_and_return;
|
||
162 | } |
||
163 | |||
164 | anm->record = -1;
|
||
165 | return 0; |
||
166 | |||
167 | invalid:
|
||
168 | av_log_ask_for_sample(s, NULL);
|
||
169 | ret = AVERROR_INVALIDDATA; |
||
170 | |||
171 | close_and_return:
|
||
172 | av_close_input_stream(s); |
||
173 | return ret;
|
||
174 | } |
||
175 | |||
176 | static int read_packet(AVFormatContext *s, |
||
177 | AVPacket *pkt) |
||
178 | { |
||
179 | AnmDemuxContext *anm = s->priv_data; |
||
180 | ae628ec1 | Anton Khirnov | AVIOContext *pb = s->pb; |
181 | e6565055 | Peter Ross | Page *p; |
182 | int tmp, record_size;
|
||
183 | |||
184 | 66e5b1df | Anton Khirnov | if (s->pb->eof_reached)
|
185 | e6565055 | Peter Ross | return AVERROR(EIO);
|
186 | |||
187 | if (anm->page < 0) |
||
188 | cbd3441e | Peter Ross | return anm->page;
|
189 | e6565055 | Peter Ross | |
190 | repeat:
|
||
191 | p = &anm->pt[anm->page]; |
||
192 | |||
193 | /* parse page header */
|
||
194 | if (anm->record < 0) { |
||
195 | 6b4aa5da | Anton Khirnov | avio_seek(pb, anm->page_table_offset + MAX_PAGES*6 + (anm->page<<16), SEEK_SET); |
196 | 45a8a02a | Anton Khirnov | avio_skip(pb, 8 + 2*p->nb_records); |
197 | e6565055 | Peter Ross | anm->record = 0;
|
198 | } |
||
199 | |||
200 | /* if we have fetched all records in this page, then find the
|
||
201 | next page and repeat */
|
||
202 | if (anm->record >= p->nb_records) {
|
||
203 | anm->page = find_record(anm, p->base_record + p->nb_records); |
||
204 | if (anm->page < 0) |
||
205 | return anm->page;
|
||
206 | anm->record = -1;
|
||
207 | goto repeat;
|
||
208 | } |
||
209 | |||
210 | /* fetch record size */
|
||
211 | a2704c97 | Anton Khirnov | tmp = avio_tell(pb); |
212 | 6b4aa5da | Anton Khirnov | avio_seek(pb, anm->page_table_offset + MAX_PAGES*6 + (anm->page<<16) + |
213 | e6565055 | Peter Ross | 8 + anm->record * 2, SEEK_SET); |
214 | b7effd4e | Anton Khirnov | record_size = avio_rl16(pb); |
215 | 6b4aa5da | Anton Khirnov | avio_seek(pb, tmp, SEEK_SET); |
216 | e6565055 | Peter Ross | |
217 | /* fetch record */
|
||
218 | pkt->size = av_get_packet(s->pb, pkt, record_size); |
||
219 | if (pkt->size < 0) |
||
220 | return pkt->size;
|
||
221 | if (p->base_record + anm->record == 0) |
||
222 | cc947f04 | Jean-Daniel Dupas | pkt->flags |= AV_PKT_FLAG_KEY; |
223 | e6565055 | Peter Ross | |
224 | anm->record++; |
||
225 | return 0; |
||
226 | } |
||
227 | |||
228 | c6610a21 | Diego Elio Pettenò | AVInputFormat ff_anm_demuxer = { |
229 | e6565055 | Peter Ross | "anm",
|
230 | NULL_IF_CONFIG_SMALL("Deluxe Paint Animation"),
|
||
231 | sizeof(AnmDemuxContext),
|
||
232 | probe, |
||
233 | read_header, |
||
234 | read_packet, |
||
235 | }; |