Main Page
Related Pages
Modules
Data Structures
Files
Examples
File List
Globals
libavformat
anm.c
Go to the documentation of this file.
1
/*
2
* Deluxe Paint Animation demuxer
3
* Copyright (c) 2009 Peter Ross
4
*
5
* This file is part of Libav.
6
*
7
* Libav 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
* Libav 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 Libav; if not, write to the Free Software
19
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
*/
21
27
#include "
libavutil/intreadwrite.h
"
28
#include "
avformat.h
"
29
#include "
internal.h
"
30
31
typedef
struct
{
32
int
base_record
;
33
unsigned
int
nb_records
;
34
int
size
;
35
}
Page
;
36
37
typedef
struct
{
38
unsigned
int
nb_pages
;
39
unsigned
int
nb_records
;
40
int
page_table_offset
;
41
#define MAX_PAGES 256
42
Page pt[MAX_PAGES];
43
int page;
44
int record;
45
} AnmDemuxContext;
46
47
#define LPF_TAG MKTAG('L','P','F',' ')
48
#define ANIM_TAG MKTAG('A','N','I','M')
49
50
static
int
probe
(
AVProbeData
*p)
51
{
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
;
57
return
0;
58
}
59
63
static
int
find_record
(
const
AnmDemuxContext
*anm,
int
record)
64
{
65
int
i;
66
67
if
(record >= anm->
nb_records
)
68
return
AVERROR_EOF
;
69
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
)
73
return
i;
74
}
75
76
return
AVERROR_INVALIDDATA
;
77
}
78
79
static
int
read_header
(
AVFormatContext
*s,
80
AVFormatParameters
*ap)
81
{
82
AnmDemuxContext
*anm = s->
priv_data
;
83
AVIOContext
*pb = s->
pb
;
84
AVStream
*st;
85
int
i, ret;
86
87
avio_skip
(pb, 4);
/* magic number */
88
if
(
avio_rl16
(pb) !=
MAX_PAGES
) {
89
av_log_ask_for_sample
(s,
"max_pages != "
AV_STRINGIFY
(
MAX_PAGES
)
"\n"
);
90
return
AVERROR_INVALIDDATA
;
91
}
92
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
;
99
100
/* video stream */
101
st =
avformat_new_stream
(s,
NULL
);
102
if
(!st)
103
return
AVERROR
(ENOMEM);
104
st->
codec
->
codec_type
=
AVMEDIA_TYPE_VIDEO
;
105
st->
codec
->
codec_id
=
CODEC_ID_ANM
;
106
st->
codec
->
codec_tag
= 0;
/* no fourcc */
107
st->
codec
->
width
=
avio_rl16
(pb);
108
st->
codec
->
height
=
avio_rl16
(pb);
109
if
(
avio_r8
(pb) != 0)
110
goto
invalid;
111
avio_skip
(pb, 1);
/* frame rate multiplier info */
112
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);
116
117
avio_skip
(pb, 1);
/* last_delta_valid */
118
119
if
(
avio_r8
(pb) != 0)
120
goto
invalid;
121
122
if
(
avio_r8
(pb) != 1)
123
goto
invalid;
124
125
avio_skip
(pb, 1);
/* other recs per frame */
126
127
if
(
avio_r8
(pb) != 1)
128
goto
invalid;
129
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));
133
avio_skip
(pb, 58);
134
135
/* color cycling and palette data */
136
st->
codec
->
extradata_size
= 16*8 + 4*256;
137
st->
codec
->
extradata
=
av_mallocz
(st->
codec
->
extradata_size
+
FF_INPUT_BUFFER_PADDING_SIZE
);
138
if
(!st->
codec
->
extradata
) {
139
ret =
AVERROR
(ENOMEM);
140
goto
fail;
141
}
142
ret =
avio_read
(pb, st->
codec
->
extradata
, st->
codec
->
extradata_size
);
143
if
(ret < 0)
144
goto
fail;
145
146
/* read page table */
147
ret =
avio_seek
(pb, anm->
page_table_offset
, SEEK_SET);
148
if
(ret < 0)
149
goto
fail;
150
151
for
(i = 0; i <
MAX_PAGES
; i++) {
152
Page
*p = &anm->
pt
[i];
153
p->
base_record
=
avio_rl16
(pb);
154
p->
nb_records
=
avio_rl16
(pb);
155
p->
size
=
avio_rl16
(pb);
156
}
157
158
/* find page of first frame */
159
anm->
page
=
find_record
(anm, 0);
160
if
(anm->
page
< 0) {
161
ret = anm->
page
;
162
goto
fail;
163
}
164
165
anm->
record
= -1;
166
return
0;
167
168
invalid:
169
av_log_ask_for_sample
(s,
NULL
);
170
ret =
AVERROR_INVALIDDATA
;
171
172
fail:
173
return
ret;
174
}
175
176
static
int
read_packet
(
AVFormatContext
*s,
177
AVPacket
*pkt)
178
{
179
AnmDemuxContext
*anm = s->
priv_data
;
180
AVIOContext
*pb = s->
pb
;
181
Page
*p;
182
int
tmp, record_size;
183
184
if
(s->
pb
->
eof_reached
)
185
return
AVERROR
(EIO);
186
187
if
(anm->
page
< 0)
188
return
anm->
page
;
189
190
repeat:
191
p = &anm->
pt
[anm->
page
];
192
193
/* parse page header */
194
if
(anm->
record
< 0) {
195
avio_seek
(pb, anm->
page_table_offset
+
MAX_PAGES
*6 + (anm->
page
<<16), SEEK_SET);
196
avio_skip
(pb, 8 + 2*p->
nb_records
);
197
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
tmp =
avio_tell
(pb);
212
avio_seek
(pb, anm->
page_table_offset
+
MAX_PAGES
*6 + (anm->
page
<<16) +
213
8 + anm->
record
* 2, SEEK_SET);
214
record_size =
avio_rl16
(pb);
215
avio_seek
(pb, tmp, SEEK_SET);
216
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
pkt->
flags
|=
AV_PKT_FLAG_KEY
;
223
224
anm->
record
++;
225
return
0;
226
}
227
228
AVInputFormat
ff_anm_demuxer
= {
229
.
name
=
"anm"
,
230
.long_name =
NULL_IF_CONFIG_SMALL
(
"Deluxe Paint Animation"
),
231
.priv_data_size =
sizeof
(
AnmDemuxContext
),
232
.
read_probe
=
probe
,
233
.
read_header
=
read_header
,
234
.
read_packet
=
read_packet
,
235
};