diff --git a/libavformat/apngdec.c b/libavformat/apngdec.c index 1e0f1c7c13..d766a87105 100644 --- a/libavformat/apngdec.c +++ b/libavformat/apngdec.c @@ -24,10 +24,6 @@ * APNG demuxer. * @see https://wiki.mozilla.org/APNG_Specification * @see http://www.w3.org/TR/PNG - * - * Not supported (yet): - * - streams with chunks other than fcTL / fdAT / IEND after the first fcTL - * - streams with multiple fdAT chunks after an fcTL one */ #include "avformat.h" @@ -325,8 +321,6 @@ static int apng_read_packet(AVFormatContext *s, AVPacket *pkt) * and needed next: * 4 (length) * 4 (tag (must be fdAT or IDAT)) - * - * TODO: support multiple fdAT following an fcTL */ /* if num_play is not 1, then the seekback is already guaranteed */ if (ctx->num_play == 1 && (ret = ffio_ensure_seekback(pb, 46)) < 0) @@ -350,15 +344,35 @@ static int apng_read_packet(AVFormatContext *s, AVPacket *pkt) tag != MKTAG('I', 'D', 'A', 'T')) return AVERROR_INVALIDDATA; - if ((ret = avio_seek(pb, -46, SEEK_CUR)) < 0) - return ret; - size = 38 /* fcTL */ + 8 /* len, tag */ + len + 4 /* crc */; if (size > INT_MAX) return AVERROR(EINVAL); - if ((ret = av_get_packet(pb, pkt, size)) < 0) + if ((ret = avio_seek(pb, -46, SEEK_CUR)) < 0 || + (ret = av_append_packet(pb, pkt, size)) < 0) return ret; + + if (ctx->num_play == 1 && (ret = ffio_ensure_seekback(pb, 8)) < 0) + return ret; + + len = avio_rb32(pb); + tag = avio_rl32(pb); + while (tag && + tag != MKTAG('f', 'c', 'T', 'L') && + tag != MKTAG('I', 'E', 'N', 'D')) { + if (len > 0x7fffffff) + return AVERROR_INVALIDDATA; + if ((ret = avio_seek(pb, -8, SEEK_CUR)) < 0 || + (ret = av_append_packet(pb, pkt, len + 12)) < 0) + return ret; + if (ctx->num_play == 1 && (ret = ffio_ensure_seekback(pb, 8)) < 0) + return ret; + len = avio_rb32(pb); + tag = avio_rl32(pb); + } + if ((ret = avio_seek(pb, -8, SEEK_CUR)) < 0) + return ret; + if (ctx->is_key_frame) pkt->flags |= AV_PKT_FLAG_KEY; return ret;