2 * Deluxe Paint Animation demuxer
3 * Copyright (c) 2009 Peter Ross
5 * This file is part of FFmpeg.
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.
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.
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
24 * Deluxe Paint Animation demuxer
27 #include "libavutil/intreadwrite.h"
33 unsigned int nb_records
;
37 typedef struct AnmDemuxContext
{
38 unsigned int nb_pages
; /**< total pages in file */
39 unsigned int nb_records
; /**< total records in file */
40 int page_table_offset
;
41 #define MAX_PAGES 256 /**< Deluxe Paint hardcoded value */
42 Page pt
[MAX_PAGES
]; /**< page table */
43 int page
; /**< current page (or AVERROR_xxx code) */
44 int record
; /**< current record (with in page) */
47 #define LPF_TAG MKTAG('L','P','F',' ')
48 #define ANIM_TAG MKTAG('A','N','I','M')
50 static int probe(const AVProbeData
*p
)
52 /* verify tags and video dimensions */
53 if (AV_RL32(&p
->buf
[0]) == LPF_TAG
&&
54 AV_RL32(&p
->buf
[16]) == ANIM_TAG
&&
55 AV_RL16(&p
->buf
[20]) && AV_RL16(&p
->buf
[22]))
56 return AVPROBE_SCORE_MAX
;
61 * @return page containing the requested record or AVERROR_XXX
63 static int find_record(const AnmDemuxContext
*anm
, int record
)
67 if (record
>= anm
->nb_records
)
70 for (i
= 0; i
< MAX_PAGES
; i
++) {
71 const Page
*p
= &anm
->pt
[i
];
72 if (p
->nb_records
> 0 && record
>= p
->base_record
&& record
< p
->base_record
+ p
->nb_records
)
76 return AVERROR_INVALIDDATA
;
79 static int read_header(AVFormatContext
*s
)
81 AnmDemuxContext
*anm
= s
->priv_data
;
82 AVIOContext
*pb
= s
->pb
;
86 avio_skip(pb
, 4); /* magic number */
87 if (avio_rl16(pb
) != MAX_PAGES
) {
88 avpriv_request_sample(s
, "max_pages != " AV_STRINGIFY(MAX_PAGES
));
89 return AVERROR_PATCHWELCOME
;
92 anm
->nb_pages
= avio_rl16(pb
);
93 anm
->nb_records
= avio_rl32(pb
);
94 avio_skip(pb
, 2); /* max records per page */
95 anm
->page_table_offset
= avio_rl16(pb
);
96 if (avio_rl32(pb
) != ANIM_TAG
)
97 return AVERROR_INVALIDDATA
;
100 st
= avformat_new_stream(s
, NULL
);
102 return AVERROR(ENOMEM
);
103 st
->codecpar
->codec_type
= AVMEDIA_TYPE_VIDEO
;
104 st
->codecpar
->codec_id
= AV_CODEC_ID_ANM
;
105 st
->codecpar
->codec_tag
= 0; /* no fourcc */
106 st
->codecpar
->width
= avio_rl16(pb
);
107 st
->codecpar
->height
= avio_rl16(pb
);
108 if (avio_r8(pb
) != 0)
110 avio_skip(pb
, 1); /* frame rate multiplier info */
112 /* ignore last delta record (used for looping) */
113 if (avio_r8(pb
)) /* has_last_delta */
114 anm
->nb_records
= FFMAX(anm
->nb_records
- 1, 0);
116 avio_skip(pb
, 1); /* last_delta_valid */
118 if (avio_r8(pb
) != 0)
121 if (avio_r8(pb
) != 1)
124 avio_skip(pb
, 1); /* other recs per frame */
126 if (avio_r8(pb
) != 1)
129 avio_skip(pb
, 32); /* record_types */
130 st
->nb_frames
= avio_rl32(pb
);
131 avpriv_set_pts_info(st
, 64, 1, avio_rl16(pb
));
134 /* color cycling and palette data */
135 ret
= ff_get_extradata(s
, st
->codecpar
, s
->pb
, 16*8 + 4*256);
139 /* read page table */
140 ret
= avio_seek(pb
, anm
->page_table_offset
, SEEK_SET
);
144 for (i
= 0; i
< MAX_PAGES
; i
++) {
145 Page
*p
= &anm
->pt
[i
];
146 p
->base_record
= avio_rl16(pb
);
147 p
->nb_records
= avio_rl16(pb
);
148 p
->size
= avio_rl16(pb
);
151 /* find page of first frame */
152 anm
->page
= find_record(anm
, 0);
161 avpriv_request_sample(s
, "Invalid header element");
162 return AVERROR_PATCHWELCOME
;
165 static int read_packet(AVFormatContext
*s
,
168 AnmDemuxContext
*anm
= s
->priv_data
;
169 AVIOContext
*pb
= s
->pb
;
171 int tmp
, record_size
;
173 if (avio_feof(s
->pb
))
180 p
= &anm
->pt
[anm
->page
];
182 /* parse page header */
183 if (anm
->record
< 0) {
184 avio_seek(pb
, anm
->page_table_offset
+ MAX_PAGES
*6 + (anm
->page
<<16), SEEK_SET
);
185 avio_skip(pb
, 8 + 2*p
->nb_records
);
189 /* if we have fetched all records in this page, then find the
190 next page and repeat */
191 if (anm
->record
>= p
->nb_records
) {
192 anm
->page
= find_record(anm
, p
->base_record
+ p
->nb_records
);
199 /* fetch record size */
201 avio_seek(pb
, anm
->page_table_offset
+ MAX_PAGES
*6 + (anm
->page
<<16) +
202 8 + anm
->record
* 2, SEEK_SET
);
203 record_size
= avio_rl16(pb
);
204 avio_seek(pb
, tmp
, SEEK_SET
);
207 pkt
->size
= av_get_packet(s
->pb
, pkt
, record_size
);
210 if (p
->base_record
+ anm
->record
== 0)
211 pkt
->flags
|= AV_PKT_FLAG_KEY
;
217 AVInputFormat ff_anm_demuxer
= {
219 .long_name
= NULL_IF_CONFIG_SMALL("Deluxe Paint Animation"),
220 .priv_data_size
= sizeof(AnmDemuxContext
),
222 .read_header
= read_header
,
223 .read_packet
= read_packet
,