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"
34 unsigned int nb_records
;
38 typedef struct AnmDemuxContext
{
39 unsigned int nb_pages
; /**< total pages in file */
40 unsigned int nb_records
; /**< total records in file */
41 int page_table_offset
;
42 #define MAX_PAGES 256 /**< Deluxe Paint hardcoded value */
43 Page pt
[MAX_PAGES
]; /**< page table */
44 int page
; /**< current page (or AVERROR_xxx code) */
45 int record
; /**< current record (with in page) */
48 #define LPF_TAG MKTAG('L','P','F',' ')
49 #define ANIM_TAG MKTAG('A','N','I','M')
51 static int probe(const AVProbeData
*p
)
53 /* verify tags and video dimensions */
54 if (AV_RL32(&p
->buf
[0]) == LPF_TAG
&&
55 AV_RL32(&p
->buf
[16]) == ANIM_TAG
&&
56 AV_RL16(&p
->buf
[20]) && AV_RL16(&p
->buf
[22]))
57 return AVPROBE_SCORE_MAX
;
62 * @return page containing the requested record or AVERROR_XXX
64 static int find_record(const AnmDemuxContext
*anm
, int record
)
68 if (record
>= anm
->nb_records
)
71 for (i
= 0; i
< MAX_PAGES
; i
++) {
72 const Page
*p
= &anm
->pt
[i
];
73 if (p
->nb_records
> 0 && record
>= p
->base_record
&& record
< p
->base_record
+ p
->nb_records
)
77 return AVERROR_INVALIDDATA
;
80 static int read_header(AVFormatContext
*s
)
82 AnmDemuxContext
*anm
= s
->priv_data
;
83 AVIOContext
*pb
= s
->pb
;
87 avio_skip(pb
, 4); /* magic number */
88 if (avio_rl16(pb
) != MAX_PAGES
) {
89 avpriv_request_sample(s
, "max_pages != " AV_STRINGIFY(MAX_PAGES
));
90 return AVERROR_PATCHWELCOME
;
93 anm
->nb_pages
= avio_rl16(pb
);
94 anm
->nb_records
= avio_rl32(pb
);
95 avio_skip(pb
, 2); /* max records per page */
96 anm
->page_table_offset
= avio_rl16(pb
);
97 if (avio_rl32(pb
) != ANIM_TAG
)
98 return AVERROR_INVALIDDATA
;
101 st
= avformat_new_stream(s
, NULL
);
103 return AVERROR(ENOMEM
);
104 st
->codecpar
->codec_type
= AVMEDIA_TYPE_VIDEO
;
105 st
->codecpar
->codec_id
= AV_CODEC_ID_ANM
;
106 st
->codecpar
->codec_tag
= 0; /* no fourcc */
107 st
->codecpar
->width
= avio_rl16(pb
);
108 st
->codecpar
->height
= avio_rl16(pb
);
109 if (avio_r8(pb
) != 0)
111 avio_skip(pb
, 1); /* frame rate multiplier info */
113 /* ignore last delta record (used for looping) */
114 if (avio_r8(pb
)) /* has_last_delta */
115 anm
->nb_records
= FFMAX(anm
->nb_records
- 1, 0);
117 avio_skip(pb
, 1); /* last_delta_valid */
119 if (avio_r8(pb
) != 0)
122 if (avio_r8(pb
) != 1)
125 avio_skip(pb
, 1); /* other recs per frame */
127 if (avio_r8(pb
) != 1)
130 avio_skip(pb
, 32); /* record_types */
131 st
->nb_frames
= avio_rl32(pb
);
132 avpriv_set_pts_info(st
, 64, 1, avio_rl16(pb
));
135 /* color cycling and palette data */
136 ret
= ff_get_extradata(s
, st
->codecpar
, s
->pb
, 16*8 + 4*256);
140 /* read page table */
141 ret
= avio_seek(pb
, anm
->page_table_offset
, SEEK_SET
);
145 for (i
= 0; i
< MAX_PAGES
; i
++) {
146 Page
*p
= &anm
->pt
[i
];
147 p
->base_record
= avio_rl16(pb
);
148 p
->nb_records
= avio_rl16(pb
);
149 p
->size
= avio_rl16(pb
);
152 /* find page of first frame */
153 anm
->page
= find_record(anm
, 0);
162 avpriv_request_sample(s
, "Invalid header element");
163 return AVERROR_PATCHWELCOME
;
166 static int read_packet(AVFormatContext
*s
,
169 AnmDemuxContext
*anm
= s
->priv_data
;
170 AVIOContext
*pb
= s
->pb
;
172 int tmp
, record_size
;
174 if (avio_feof(s
->pb
))
181 p
= &anm
->pt
[anm
->page
];
183 /* parse page header */
184 if (anm
->record
< 0) {
185 avio_seek(pb
, anm
->page_table_offset
+ MAX_PAGES
*6 + (anm
->page
<<16), SEEK_SET
);
186 avio_skip(pb
, 8 + 2*p
->nb_records
);
190 /* if we have fetched all records in this page, then find the
191 next page and repeat */
192 if (anm
->record
>= p
->nb_records
) {
193 anm
->page
= find_record(anm
, p
->base_record
+ p
->nb_records
);
200 /* fetch record size */
202 avio_seek(pb
, anm
->page_table_offset
+ MAX_PAGES
*6 + (anm
->page
<<16) +
203 8 + anm
->record
* 2, SEEK_SET
);
204 record_size
= avio_rl16(pb
);
205 avio_seek(pb
, tmp
, SEEK_SET
);
208 pkt
->size
= av_get_packet(s
->pb
, pkt
, record_size
);
211 if (p
->base_record
+ anm
->record
== 0)
212 pkt
->flags
|= AV_PKT_FLAG_KEY
;
218 const FFInputFormat ff_anm_demuxer
= {
220 .p
.long_name
= NULL_IF_CONFIG_SMALL("Deluxe Paint Animation"),
221 .priv_data_size
= sizeof(AnmDemuxContext
),
223 .read_header
= read_header
,
224 .read_packet
= read_packet
,