3 * Copyright (c) 2014 Benoit Fouet
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
25 * @see https://wiki.mozilla.org/APNG_Specification
26 * @see http://www.w3.org/TR/PNG
30 #include "avio_internal.h"
33 #include "libavutil/imgutils.h"
34 #include "libavutil/intreadwrite.h"
35 #include "libavutil/mem.h"
36 #include "libavutil/opt.h"
37 #include "libavcodec/apng.h"
38 #include "libavcodec/png.h"
39 #include "libavcodec/bytestream.h"
41 #define DEFAULT_APNG_FPS 15
43 typedef struct APNGDemuxContext
{
63 * To be a valid APNG file, we mandate, in this order:
71 static int apng_probe(const AVProbeData
*p
)
77 bytestream2_init(&gb
, p
->buf
, p
->buf_size
);
79 if (bytestream2_get_be64(&gb
) != PNGSIG
)
83 len
= bytestream2_get_be32(&gb
);
87 tag
= bytestream2_get_le32(&gb
);
88 /* we don't check IDAT size, as this is the last tag
89 * we check, and it may be larger than the probe buffer */
90 if (tag
!= MKTAG('I', 'D', 'A', 'T') &&
91 len
+ 4 > bytestream2_get_bytes_left(&gb
))
95 case MKTAG('I', 'H', 'D', 'R'):
98 if (av_image_check_size(bytestream2_get_be32(&gb
), bytestream2_get_be32(&gb
), 0, NULL
))
100 bytestream2_skip(&gb
, 9);
103 case MKTAG('a', 'c', 'T', 'L'):
106 bytestream2_get_be32(&gb
) == 0) /* 0 is not a valid value for number of frames */
108 bytestream2_skip(&gb
, 8);
111 case MKTAG('I', 'D', 'A', 'T'):
116 /* skip other tags */
117 bytestream2_skip(&gb
, len
+ 4);
123 return AVPROBE_SCORE_MAX
;
126 static int append_extradata(AVCodecParameters
*par
, AVIOContext
*pb
, int len
)
128 int previous_size
= par
->extradata_size
;
130 uint8_t *new_extradata
;
132 if (len
> INT_MAX
- AV_INPUT_BUFFER_PADDING_SIZE
- previous_size
)
133 return AVERROR_INVALIDDATA
;
135 new_size
= previous_size
+ len
;
136 new_extradata
= av_realloc(par
->extradata
, new_size
+ AV_INPUT_BUFFER_PADDING_SIZE
);
138 return AVERROR(ENOMEM
);
139 memset(new_extradata
+ new_size
, 0, AV_INPUT_BUFFER_PADDING_SIZE
);
140 par
->extradata
= new_extradata
;
141 par
->extradata_size
= new_size
;
143 if ((ret
= ffio_read_size(pb
, par
->extradata
+ previous_size
, len
)) < 0)
146 return previous_size
;
149 static int apng_read_header(AVFormatContext
*s
)
151 APNGDemuxContext
*ctx
= s
->priv_data
;
152 AVIOContext
*pb
= s
->pb
;
159 if (avio_rb64(pb
) != PNGSIG
)
160 return AVERROR_INVALIDDATA
;
162 /* parse IHDR (must be first chunk) */
165 if (len
!= 13 || tag
!= MKTAG('I', 'H', 'D', 'R'))
166 return AVERROR_INVALIDDATA
;
168 st
= avformat_new_stream(s
, NULL
);
170 return AVERROR(ENOMEM
);
172 /* set the timebase to something large enough (1/100,000 of second)
173 * to hopefully cope with all sane frame durations */
174 avpriv_set_pts_info(st
, 64, 1, 100000);
175 st
->codecpar
->codec_type
= AVMEDIA_TYPE_VIDEO
;
176 st
->codecpar
->codec_id
= AV_CODEC_ID_APNG
;
177 st
->codecpar
->width
= avio_rb32(pb
);
178 st
->codecpar
->height
= avio_rb32(pb
);
179 if ((ret
= av_image_check_size(st
->codecpar
->width
, st
->codecpar
->height
, 0, s
)) < 0)
182 /* extradata will contain every chunk up to the first fcTL (excluded) */
183 ret
= ff_alloc_extradata(st
->codecpar
, len
+ 12);
186 AV_WB32(st
->codecpar
->extradata
, len
);
187 AV_WL32(st
->codecpar
->extradata
+4, tag
);
188 AV_WB32(st
->codecpar
->extradata
+8, st
->codecpar
->width
);
189 AV_WB32(st
->codecpar
->extradata
+12, st
->codecpar
->height
);
190 if ((ret
= ffio_read_size(pb
, st
->codecpar
->extradata
+ 16, 9)) < 0)
194 if (acTL_found
&& ctx
->num_play
!= 1) {
195 int64_t size
= avio_size(pb
);
196 int64_t offset
= avio_tell(pb
);
199 } else if (offset
< 0) {
201 } else if ((ret
= ffio_ensure_seekback(pb
, size
- offset
)) < 0) {
202 av_log(s
, AV_LOG_WARNING
, "Could not ensure seekback, will not loop\n");
206 if ((ctx
->num_play
== 1 || !acTL_found
) &&
207 ((ret
= ffio_ensure_seekback(pb
, 4 /* len */ + 4 /* tag */)) < 0))
211 if (len
> INT_MAX
- 12)
212 return AVERROR_INVALIDDATA
;
216 case MKTAG('a', 'c', 'T', 'L'):
217 if ((ret
= avio_seek(pb
, -8, SEEK_CUR
)) < 0 ||
218 (ret
= append_extradata(st
->codecpar
, pb
, len
+ 12)) < 0)
221 ctx
->num_frames
= AV_RB32(st
->codecpar
->extradata
+ ret
+ 8);
222 ctx
->num_play
= AV_RB32(st
->codecpar
->extradata
+ ret
+ 12);
223 av_log(s
, AV_LOG_DEBUG
, "num_frames: %"PRIu32
", num_play: %"PRIu32
"\n",
224 ctx
->num_frames
, ctx
->num_play
);
226 case MKTAG('f', 'c', 'T', 'L'):
227 if (!acTL_found
|| len
!= APNG_FCTL_CHUNK_SIZE
) {
228 return AVERROR_INVALIDDATA
;
230 if ((ret
= avio_seek(pb
, -8, SEEK_CUR
)) < 0)
234 if ((ret
= avio_seek(pb
, -8, SEEK_CUR
)) < 0 ||
235 (ret
= append_extradata(st
->codecpar
, pb
, len
+ 12)) < 0)
241 static int decode_fctl_chunk(AVFormatContext
*s
, APNGDemuxContext
*ctx
, AVPacket
*pkt
)
243 uint32_t sequence_number
, width
, height
, x_offset
, y_offset
;
244 uint16_t delay_num
, delay_den
;
245 uint8_t dispose_op
, blend_op
;
247 sequence_number
= avio_rb32(s
->pb
);
248 width
= avio_rb32(s
->pb
);
249 height
= avio_rb32(s
->pb
);
250 x_offset
= avio_rb32(s
->pb
);
251 y_offset
= avio_rb32(s
->pb
);
252 delay_num
= avio_rb16(s
->pb
);
253 delay_den
= avio_rb16(s
->pb
);
254 dispose_op
= avio_r8(s
->pb
);
255 blend_op
= avio_r8(s
->pb
);
256 avio_skip(s
->pb
, 4); /* crc */
258 /* default is hundredths of seconds */
261 if (!delay_num
|| (ctx
->max_fps
&& delay_den
/ delay_num
> ctx
->max_fps
)) {
263 delay_den
= ctx
->default_fps
;
265 ctx
->pkt_duration
= av_rescale_q(delay_num
,
266 (AVRational
){ 1, delay_den
},
267 s
->streams
[0]->time_base
);
269 av_log(s
, AV_LOG_DEBUG
, "%s: "
270 "sequence_number: %"PRId32
", "
272 "height: %"PRIu32
", "
273 "x_offset: %"PRIu32
", "
274 "y_offset: %"PRIu32
", "
275 "delay_num: %"PRIu16
", "
276 "delay_den: %"PRIu16
", "
290 if (width
!= s
->streams
[0]->codecpar
->width
||
291 height
!= s
->streams
[0]->codecpar
->height
||
294 if (sequence_number
== 0 ||
295 x_offset
>= s
->streams
[0]->codecpar
->width
||
296 width
> s
->streams
[0]->codecpar
->width
- x_offset
||
297 y_offset
>= s
->streams
[0]->codecpar
->height
||
298 height
> s
->streams
[0]->codecpar
->height
- y_offset
)
299 return AVERROR_INVALIDDATA
;
300 ctx
->is_key_frame
= 0;
302 if (sequence_number
== 0 && dispose_op
== APNG_DISPOSE_OP_PREVIOUS
)
303 dispose_op
= APNG_DISPOSE_OP_BACKGROUND
;
304 ctx
->is_key_frame
= dispose_op
== APNG_DISPOSE_OP_BACKGROUND
||
305 blend_op
== APNG_BLEND_OP_SOURCE
;
311 static int apng_read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
313 APNGDemuxContext
*ctx
= s
->priv_data
;
316 AVIOContext
*pb
= s
->pb
;
320 * fcTL chunk length, in bytes:
327 * 4 (tag (must be fdAT or IDAT))
329 /* if num_play is not 1, then the seekback is already guaranteed */
330 if (ctx
->num_play
== 1 && (ret
= ffio_ensure_seekback(pb
, 46)) < 0)
340 case MKTAG('f', 'c', 'T', 'L'):
341 if (len
!= APNG_FCTL_CHUNK_SIZE
)
342 return AVERROR_INVALIDDATA
;
344 if ((ret
= decode_fctl_chunk(s
, ctx
, pkt
)) < 0)
347 /* fcTL must precede fdAT or IDAT */
350 if (len
> 0x7fffffff ||
351 tag
!= MKTAG('f', 'd', 'A', 'T') &&
352 tag
!= MKTAG('I', 'D', 'A', 'T'))
353 return AVERROR_INVALIDDATA
;
355 size
= 38 /* fcTL */ + 8 /* len, tag */ + len
+ 4 /* crc */;
357 return AVERROR(EINVAL
);
359 if ((ret
= avio_seek(pb
, -46, SEEK_CUR
)) < 0 ||
360 (ret
= av_append_packet(pb
, pkt
, size
)) < 0)
363 if (ctx
->num_play
== 1 && (ret
= ffio_ensure_seekback(pb
, 8)) < 0)
369 tag
!= MKTAG('f', 'c', 'T', 'L') &&
370 tag
!= MKTAG('I', 'E', 'N', 'D')) {
371 if (len
> 0x7fffffff)
372 return AVERROR_INVALIDDATA
;
373 if ((ret
= avio_seek(pb
, -8, SEEK_CUR
)) < 0 ||
374 (ret
= av_append_packet(pb
, pkt
, len
+ 12)) < 0)
376 if (ctx
->num_play
== 1 && (ret
= ffio_ensure_seekback(pb
, 8)) < 0)
381 if ((ret
= avio_seek(pb
, -8, SEEK_CUR
)) < 0)
384 if (ctx
->is_key_frame
)
385 pkt
->flags
|= AV_PKT_FLAG_KEY
;
386 pkt
->pts
= pkt
->dts
= AV_NOPTS_VALUE
;
387 pkt
->duration
= ctx
->pkt_duration
;
389 case MKTAG('I', 'E', 'N', 'D'):
391 if (ctx
->ignore_loop
|| ctx
->num_play
>= 1 && ctx
->cur_loop
== ctx
->num_play
) {
392 avio_seek(pb
, -8, SEEK_CUR
);
395 if ((ret
= avio_seek(pb
, s
->streams
[0]->codecpar
->extradata_size
+ 8, SEEK_SET
)) < 0)
399 avpriv_request_sample(s
, "In-stream tag=%s (0x%08"PRIX32
") len=%"PRIu32
,
400 av_fourcc2str(tag
), tag
, len
);
401 avio_skip(pb
, len
+ 4);
404 /* Handle the unsupported yet cases */
405 return AVERROR_PATCHWELCOME
;
408 static const AVOption options
[] = {
409 { "ignore_loop", "ignore loop setting" , offsetof(APNGDemuxContext
, ignore_loop
),
410 AV_OPT_TYPE_BOOL
, { .i64
= 1 } , 0, 1 , AV_OPT_FLAG_DECODING_PARAM
},
411 { "max_fps" , "maximum framerate (0 is no limit)" , offsetof(APNGDemuxContext
, max_fps
),
412 AV_OPT_TYPE_INT
, { .i64
= 0 }, 0, INT_MAX
, AV_OPT_FLAG_DECODING_PARAM
},
413 { "default_fps", "default framerate (0 is as fast as possible)", offsetof(APNGDemuxContext
, default_fps
),
414 AV_OPT_TYPE_INT
, { .i64
= DEFAULT_APNG_FPS
}, 0, INT_MAX
, AV_OPT_FLAG_DECODING_PARAM
},
418 static const AVClass demuxer_class
= {
419 .class_name
= "APNG demuxer",
420 .item_name
= av_default_item_name
,
422 .version
= LIBAVUTIL_VERSION_INT
,
423 .category
= AV_CLASS_CATEGORY_DEMUXER
,
426 const FFInputFormat ff_apng_demuxer
= {
428 .p
.long_name
= NULL_IF_CONFIG_SMALL("Animated Portable Network Graphics"),
429 .p
.flags
= AVFMT_GENERIC_INDEX
,
430 .p
.priv_class
= &demuxer_class
,
431 .priv_data_size
= sizeof(APNGDemuxContext
),
432 .read_probe
= apng_probe
,
433 .read_header
= apng_read_header
,
434 .read_packet
= apng_read_packet
,