diff --git a/libavformat/gif.c b/libavformat/gif.c index 6b03d0a6e8..ef1ea7582d 100644 --- a/libavformat/gif.c +++ b/libavformat/gif.c @@ -68,7 +68,8 @@ static int gif_image_write_header(AVIOContext *pb, int width, int height, typedef struct { AVClass *class; /** Class for private options. */ int loop; - int64_t prev_pts; + AVPacket *prev_pkt; + int duration; } GIFContext; static int gif_write_header(AVFormatContext *s) @@ -103,13 +104,33 @@ static int gif_write_header(AVFormatContext *s) return 0; } +/* TODO: move below */ +static int flush_packet(AVFormatContext *s, AVPacket *pkt); + static int gif_write_packet(AVFormatContext *s, AVPacket *pkt) { GIFContext *gif = s->priv_data; - int size, duration; + + if (!gif->prev_pkt) { + gif->prev_pkt = av_malloc(sizeof(*gif->prev_pkt)); + if (!gif->prev_pkt) + return AVERROR(ENOMEM); + return av_copy_packet(gif->prev_pkt, pkt); + } + return flush_packet(s, pkt); +} + +static int flush_packet(AVFormatContext *s, AVPacket *new) +{ + GIFContext *gif = s->priv_data; + int size; AVIOContext *pb = s->pb; uint8_t flags = 0x4, transparent_color_index = 0x1f; const uint32_t *palette; + AVPacket *pkt = gif->prev_pkt; + + if (!pkt) + return 0; /* Mark one colour as transparent if the input palette contains at least * one colour that is more than 50% transparent. */ @@ -132,27 +153,34 @@ static int gif_write_packet(AVFormatContext *s, AVPacket *pkt) flags |= 0x1; /* Transparent Color Flag */ } - duration = pkt->pts == AV_NOPTS_VALUE ? 0 : av_clip_uint16(pkt->pts - gif->prev_pts); - gif->prev_pts = pkt->pts; + if (new && new->pts != AV_NOPTS_VALUE) + gif->duration = av_clip_uint16(new->pts - gif->prev_pkt->pts); /* graphic control extension block */ avio_w8(pb, 0x21); avio_w8(pb, 0xf9); avio_w8(pb, 0x04); /* block size */ avio_w8(pb, flags); - avio_wl16(pb, duration); + avio_wl16(pb, gif->duration); avio_w8(pb, transparent_color_index); avio_w8(pb, 0x00); avio_write(pb, pkt->data, pkt->size); + av_free_packet(gif->prev_pkt); + if (new) + av_copy_packet(gif->prev_pkt, new); + return 0; } static int gif_write_trailer(AVFormatContext *s) { + GIFContext *gif = s->priv_data; AVIOContext *pb = s->pb; + flush_packet(s, NULL); + av_freep(&gif->prev_pkt); avio_w8(pb, 0x3b); return 0; diff --git a/tests/ref/lavf/gif b/tests/ref/lavf/gif index f66d05f888..531cd1eda7 100644 --- a/tests/ref/lavf/gif +++ b/tests/ref/lavf/gif @@ -1,3 +1,3 @@ -c886d22859c033b2b0fe2d63ffcf8aef *./tests/data/lavf/lavf.gif +e35f5ea283bbcb249818e0078ec72664 *./tests/data/lavf/lavf.gif 2011766 ./tests/data/lavf/lavf.gif -./tests/data/lavf/lavf.gif CRC=0xdca4429c +./tests/data/lavf/lavf.gif CRC=0x0dc5477c