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"
32 #include "libavutil/imgutils.h"
33 #include "libavutil/intreadwrite.h"
34 #include "libavutil/opt.h"
35 #include "libavcodec/apng.h"
36 #include "libavcodec/png.h"
37 #include "libavcodec/bytestream.h"
39 #define DEFAULT_APNG_FPS 15
41 typedef struct APNGDemuxContext
{
62 * To be a valid APNG file, we mandate, in this order:
70 static int apng_probe(AVProbeData
*p
)
76 bytestream2_init(&gb
, p
->buf
, p
->buf_size
);
78 if (bytestream2_get_be64(&gb
) != PNGSIG
)
82 len
= bytestream2_get_be32(&gb
);
86 tag
= bytestream2_get_le32(&gb
);
87 /* we don't check IDAT size, as this is the last tag
88 * we check, and it may be larger than the probe buffer */
89 if (tag
!= MKTAG('I', 'D', 'A', 'T') &&
90 len
+ 4 > bytestream2_get_bytes_left(&gb
))
94 case MKTAG('I', 'H', 'D', 'R'):
97 if (av_image_check_size(bytestream2_get_be32(&gb
), bytestream2_get_be32(&gb
), 0, NULL
))
99 bytestream2_skip(&gb
, 9);
102 case MKTAG('a', 'c', 'T', 'L'):
105 bytestream2_get_be32(&gb
) == 0) /* 0 is not a valid value for number of frames */
107 bytestream2_skip(&gb
, 8);
110 case MKTAG('I', 'D', 'A', 'T'):
115 /* skip other tags */
116 bytestream2_skip(&gb
, len
+ 4);
122 return AVPROBE_SCORE_MAX
;
125 static int append_extradata(AVCodecContext
*s
, AVIOContext
*pb
, int len
)
127 int previous_size
= s
->extradata_size
;
129 uint8_t *new_extradata
;
131 if (previous_size
> INT_MAX
- len
)
132 return AVERROR_INVALIDDATA
;
134 new_size
= previous_size
+ len
;
135 new_extradata
= av_realloc(s
->extradata
, new_size
+ FF_INPUT_BUFFER_PADDING_SIZE
);
137 return AVERROR(ENOMEM
);
138 s
->extradata
= new_extradata
;
139 s
->extradata_size
= new_size
;
141 if ((ret
= avio_read(pb
, s
->extradata
+ previous_size
, len
)) < 0)
144 return previous_size
;
147 static int apng_read_header(AVFormatContext
*s
)
149 APNGDemuxContext
*ctx
= s
->priv_data
;
150 AVIOContext
*pb
= s
->pb
;
153 int ret
= AVERROR_INVALIDDATA
, acTL_found
= 0;
156 if (avio_rb64(pb
) != PNGSIG
)
159 /* parse IHDR (must be first chunk) */
162 if (len
!= 13 || tag
!= MKTAG('I', 'H', 'D', 'R'))
165 st
= avformat_new_stream(s
, NULL
);
167 return AVERROR(ENOMEM
);
169 /* set the timebase to something large enough (1/100,000 of second)
170 * to hopefully cope with all sane frame durations */
171 avpriv_set_pts_info(st
, 64, 1, 100000);
172 st
->codec
->codec_type
= AVMEDIA_TYPE_VIDEO
;
173 st
->codec
->codec_id
= AV_CODEC_ID_APNG
;
174 st
->codec
->width
= avio_rb32(pb
);
175 st
->codec
->height
= avio_rb32(pb
);
176 if ((ret
= av_image_check_size(st
->codec
->width
, st
->codec
->height
, 0, s
)) < 0)
179 /* extradata will contain every chunk up to the first fcTL (excluded) */
180 st
->codec
->extradata
= av_malloc(len
+ 12 + FF_INPUT_BUFFER_PADDING_SIZE
);
181 if (!st
->codec
->extradata
)
182 return AVERROR(ENOMEM
);
183 st
->codec
->extradata_size
= len
+ 12;
184 AV_WB32(st
->codec
->extradata
, len
);
185 AV_WL32(st
->codec
->extradata
+4, tag
);
186 AV_WB32(st
->codec
->extradata
+8, st
->codec
->width
);
187 AV_WB32(st
->codec
->extradata
+12, st
->codec
->height
);
188 if ((ret
= avio_read(pb
, st
->codec
->extradata
+16, 9)) < 0)
191 while (!avio_feof(pb
)) {
192 if (acTL_found
&& ctx
->num_play
!= 1) {
193 int64_t size
= avio_size(pb
);
194 int64_t offset
= avio_tell(pb
);
198 } 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
> 0x7fffffff) {
212 ret
= AVERROR_INVALIDDATA
;
218 case MKTAG('a', 'c', 'T', 'L'):
219 if ((ret
= avio_seek(pb
, -8, SEEK_CUR
)) < 0 ||
220 (ret
= append_extradata(st
->codec
, pb
, len
+ 12)) < 0)
223 ctx
->num_frames
= AV_RB32(st
->codec
->extradata
+ ret
+ 8);
224 ctx
->num_play
= AV_RB32(st
->codec
->extradata
+ ret
+ 12);
225 av_log(s
, AV_LOG_DEBUG
, "num_frames: %"PRIu32
", num_play: %"PRIu32
"\n",
226 ctx
->num_frames
, ctx
->num_play
);
228 case MKTAG('f', 'c', 'T', 'L'):
230 ret
= AVERROR_INVALIDDATA
;
233 if ((ret
= avio_seek(pb
, -8, SEEK_CUR
)) < 0)
237 if ((ret
= avio_seek(pb
, -8, SEEK_CUR
)) < 0 ||
238 (ret
= append_extradata(st
->codec
, pb
, len
+ 12)) < 0)
244 if (st
->codec
->extradata_size
) {
245 av_freep(&st
->codec
->extradata
);
246 st
->codec
->extradata_size
= 0;
251 static int decode_fctl_chunk(AVFormatContext
*s
, APNGDemuxContext
*ctx
, AVPacket
*pkt
)
253 uint32_t sequence_number
, width
, height
, x_offset
, y_offset
;
254 uint16_t delay_num
, delay_den
;
255 uint8_t dispose_op
, blend_op
;
257 sequence_number
= avio_rb32(s
->pb
);
258 width
= avio_rb32(s
->pb
);
259 height
= avio_rb32(s
->pb
);
260 x_offset
= avio_rb32(s
->pb
);
261 y_offset
= avio_rb32(s
->pb
);
262 delay_num
= avio_rb16(s
->pb
);
263 delay_den
= avio_rb16(s
->pb
);
264 dispose_op
= avio_r8(s
->pb
);
265 blend_op
= avio_r8(s
->pb
);
266 avio_skip(s
->pb
, 4); /* crc */
268 /* default is hundredths of seconds */
271 if (!delay_num
|| delay_den
/ delay_num
> ctx
->max_fps
) {
273 delay_den
= ctx
->default_fps
;
275 ctx
->pkt_duration
= av_rescale_q(delay_num
,
276 (AVRational
){ 1, delay_den
},
277 s
->streams
[0]->time_base
);
279 av_log(s
, AV_LOG_DEBUG
, "%s: "
280 "sequence_number: %"PRId32
", "
282 "height: %"PRIu32
", "
283 "x_offset: %"PRIu32
", "
284 "y_offset: %"PRIu32
", "
285 "delay_num: %"PRIu16
", "
286 "delay_den: %"PRIu16
", "
300 if (width
!= s
->streams
[0]->codec
->width
||
301 height
!= s
->streams
[0]->codec
->height
||
304 if (sequence_number
== 0 ||
305 x_offset
>= s
->streams
[0]->codec
->width
||
306 width
> s
->streams
[0]->codec
->width
- x_offset
||
307 y_offset
>= s
->streams
[0]->codec
->height
||
308 height
> s
->streams
[0]->codec
->height
- y_offset
)
309 return AVERROR_INVALIDDATA
;
310 ctx
->is_key_frame
= 0;
312 if (sequence_number
== 0 && dispose_op
== APNG_DISPOSE_OP_PREVIOUS
)
313 dispose_op
= APNG_DISPOSE_OP_BACKGROUND
;
314 ctx
->is_key_frame
= dispose_op
== APNG_DISPOSE_OP_BACKGROUND
||
315 blend_op
== APNG_BLEND_OP_SOURCE
;
321 static int apng_read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
323 APNGDemuxContext
*ctx
= s
->priv_data
;
326 AVIOContext
*pb
= s
->pb
;
330 * fcTL chunk length, in bytes:
337 * 4 (tag (must be fdAT or IDAT))
339 /* if num_play is not 1, then the seekback is already guaranteed */
340 if (ctx
->num_play
== 1 && (ret
= ffio_ensure_seekback(pb
, 46)) < 0)
346 case MKTAG('f', 'c', 'T', 'L'):
348 return AVERROR_INVALIDDATA
;
350 if ((ret
= decode_fctl_chunk(s
, ctx
, pkt
)) < 0)
353 /* fcTL must precede fdAT or IDAT */
356 if (len
> 0x7fffffff ||
357 tag
!= MKTAG('f', 'd', 'A', 'T') &&
358 tag
!= MKTAG('I', 'D', 'A', 'T'))
359 return AVERROR_INVALIDDATA
;
361 size
= 38 /* fcTL */ + 8 /* len, tag */ + len
+ 4 /* crc */;
363 return AVERROR(EINVAL
);
365 if ((ret
= avio_seek(pb
, -46, SEEK_CUR
)) < 0 ||
366 (ret
= av_append_packet(pb
, pkt
, size
)) < 0)
369 if (ctx
->num_play
== 1 && (ret
= ffio_ensure_seekback(pb
, 8)) < 0)
375 tag
!= MKTAG('f', 'c', 'T', 'L') &&
376 tag
!= MKTAG('I', 'E', 'N', 'D')) {
377 if (len
> 0x7fffffff)
378 return AVERROR_INVALIDDATA
;
379 if ((ret
= avio_seek(pb
, -8, SEEK_CUR
)) < 0 ||
380 (ret
= av_append_packet(pb
, pkt
, len
+ 12)) < 0)
382 if (ctx
->num_play
== 1 && (ret
= ffio_ensure_seekback(pb
, 8)) < 0)
387 if ((ret
= avio_seek(pb
, -8, SEEK_CUR
)) < 0)
390 if (ctx
->is_key_frame
)
391 pkt
->flags
|= AV_PKT_FLAG_KEY
;
392 pkt
->pts
= ctx
->pkt_pts
;
393 pkt
->duration
= ctx
->pkt_duration
;
394 ctx
->pkt_pts
+= ctx
->pkt_duration
;
396 case MKTAG('I', 'E', 'N', 'D'):
398 if (ctx
->ignore_loop
|| ctx
->num_play
>= 1 && ctx
->cur_loop
== ctx
->num_play
) {
399 avio_seek(pb
, -8, SEEK_CUR
);
402 if ((ret
= avio_seek(pb
, s
->streams
[0]->codec
->extradata_size
+ 8, SEEK_SET
)) < 0)
409 av_get_codec_tag_string(tag_buf
, sizeof(tag_buf
), tag
);
410 avpriv_request_sample(s
, "In-stream tag=%s (0x%08X) len=%"PRIu32
, tag_buf
, tag
, len
);
411 avio_skip(pb
, len
+ 4);
415 /* Handle the unsupported yet cases */
416 return AVERROR_PATCHWELCOME
;
419 static const AVOption options
[] = {
420 { "ignore_loop", "ignore loop setting" , offsetof(APNGDemuxContext
, ignore_loop
),
421 AV_OPT_TYPE_INT
, { .i64
= 1 } , 0, 1 , AV_OPT_FLAG_DECODING_PARAM
},
422 { "max_fps" , "maximum framerate (0 is no limit)" , offsetof(APNGDemuxContext
, max_fps
),
423 AV_OPT_TYPE_INT
, { .i64
= DEFAULT_APNG_FPS
}, 0, INT_MAX
, AV_OPT_FLAG_DECODING_PARAM
},
424 { "default_fps", "default framerate (0 is as fast as possible)", offsetof(APNGDemuxContext
, default_fps
),
425 AV_OPT_TYPE_INT
, { .i64
= DEFAULT_APNG_FPS
}, 0, INT_MAX
, AV_OPT_FLAG_DECODING_PARAM
},
429 static const AVClass demuxer_class
= {
430 .class_name
= "APNG demuxer",
431 .item_name
= av_default_item_name
,
433 .version
= LIBAVUTIL_VERSION_INT
,
434 .category
= AV_CLASS_CATEGORY_DEMUXER
,
437 AVInputFormat ff_apng_demuxer
= {
439 .long_name
= NULL_IF_CONFIG_SMALL("Animated Portable Network Graphics"),
440 .priv_data_size
= sizeof(APNGDemuxContext
),
441 .read_probe
= apng_probe
,
442 .read_header
= apng_read_header
,
443 .read_packet
= apng_read_packet
,
444 .flags
= AVFMT_GENERIC_INDEX
,
445 .priv_class
= &demuxer_class
,