3 * Copyright (c) 2000 Fabrice Bellard
5 * first version by Francois Revol <revol@free.fr>
7 * This file is part of FFmpeg.
9 * FFmpeg is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * FFmpeg is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with FFmpeg; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26 #include "libavutil/avassert.h"
27 #include "libavutil/imgutils.h"
28 #include "libavutil/log.h"
29 #include "libavutil/opt.h"
31 static int gif_image_write_header(AVFormatContext
*s
, int width
, int height
,
32 int loop_count
, uint32_t *palette
)
34 AVIOContext
*pb
= s
->pb
;
35 AVRational sar
= s
->streams
[0]->codec
->sample_aspect_ratio
;
39 if (sar
.num
> 0 && sar
.den
> 0) {
40 aspect
= sar
.num
* 64LL / sar
.den
- 15;
41 if (aspect
< 0 || aspect
> 255)
45 avio_write(pb
, "GIF", 3);
46 avio_write(pb
, "89a", 3);
48 avio_wl16(pb
, height
);
51 avio_w8(pb
, 0xf7); /* flags: global clut, 256 entries */
52 avio_w8(pb
, 0x1f); /* background color index */
54 for (i
= 0; i
< 256; i
++) {
55 const uint32_t v
= palette
[i
] & 0xffffff;
59 avio_w8(pb
, 0); /* flags */
60 avio_w8(pb
, 0); /* background color index */
65 if (loop_count
>= 0 ) {
66 /* "NETSCAPE EXTENSION" for looped animation GIF */
67 avio_w8(pb
, 0x21); /* GIF Extension code */
68 avio_w8(pb
, 0xff); /* Application Extension Label */
69 avio_w8(pb
, 0x0b); /* Length of Application Block */
70 avio_write(pb
, "NETSCAPE2.0", sizeof("NETSCAPE2.0") - 1);
71 avio_w8(pb
, 0x03); /* Length of Data Sub-Block */
73 avio_wl16(pb
, (uint16_t)loop_count
);
74 avio_w8(pb
, 0x00); /* Data Sub-block Terminator */
88 static int gif_write_header(AVFormatContext
*s
)
90 GIFContext
*gif
= s
->priv_data
;
91 AVCodecContext
*video_enc
;
93 uint32_t palette
[AVPALETTE_COUNT
];
95 if (s
->nb_streams
!= 1 ||
96 s
->streams
[0]->codec
->codec_type
!= AVMEDIA_TYPE_VIDEO
||
97 s
->streams
[0]->codec
->codec_id
!= AV_CODEC_ID_GIF
) {
98 av_log(s
, AV_LOG_ERROR
,
99 "GIF muxer supports only a single video GIF stream.\n");
100 return AVERROR(EINVAL
);
103 video_enc
= s
->streams
[0]->codec
;
104 width
= video_enc
->width
;
105 height
= video_enc
->height
;
107 avpriv_set_pts_info(s
->streams
[0], 64, 1, 100);
108 if (avpriv_set_systematic_pal2(palette
, video_enc
->pix_fmt
) < 0) {
109 av_assert0(video_enc
->pix_fmt
== AV_PIX_FMT_PAL8
);
110 gif_image_write_header(s
, width
, height
, gif
->loop
, NULL
);
112 gif_image_write_header(s
, width
, height
, gif
->loop
, palette
);
119 static int flush_packet(AVFormatContext
*s
, AVPacket
*new)
121 GIFContext
*gif
= s
->priv_data
;
123 AVIOContext
*pb
= s
->pb
;
124 uint8_t flags
= 0x4, transparent_color_index
= 0x1f;
125 const uint32_t *palette
;
126 AVPacket
*pkt
= gif
->prev_pkt
;
131 /* Mark one colour as transparent if the input palette contains at least
132 * one colour that is more than 50% transparent. */
133 palette
= (uint32_t*)av_packet_get_side_data(pkt
, AV_PKT_DATA_PALETTE
, &size
);
134 if (palette
&& size
!= AVPALETTE_SIZE
) {
135 av_log(s
, AV_LOG_ERROR
, "Invalid palette extradata\n");
136 return AVERROR_INVALIDDATA
;
139 unsigned i
, smallest_alpha
= 0xff;
141 for (i
= 0; i
< AVPALETTE_COUNT
; i
++) {
142 const uint32_t v
= palette
[i
];
143 if (v
>> 24 < smallest_alpha
) {
144 smallest_alpha
= v
>> 24;
145 transparent_color_index
= i
;
148 if (smallest_alpha
< 128)
149 flags
|= 0x1; /* Transparent Color Flag */
152 if (new && new->pts
!= AV_NOPTS_VALUE
)
153 gif
->duration
= av_clip_uint16(new->pts
- gif
->prev_pkt
->pts
);
154 else if (!new && gif
->last_delay
>= 0)
155 gif
->duration
= gif
->last_delay
;
157 /* graphic control extension block */
160 avio_w8(pb
, 0x04); /* block size */
162 avio_wl16(pb
, gif
->duration
);
163 avio_w8(pb
, transparent_color_index
);
166 avio_write(pb
, pkt
->data
, pkt
->size
);
168 av_free_packet(gif
->prev_pkt
);
170 av_copy_packet(gif
->prev_pkt
, new);
175 static int gif_write_packet(AVFormatContext
*s
, AVPacket
*pkt
)
177 GIFContext
*gif
= s
->priv_data
;
179 if (!gif
->prev_pkt
) {
180 gif
->prev_pkt
= av_malloc(sizeof(*gif
->prev_pkt
));
182 return AVERROR(ENOMEM
);
183 return av_copy_packet(gif
->prev_pkt
, pkt
);
185 return flush_packet(s
, pkt
);
188 static int gif_write_trailer(AVFormatContext
*s
)
190 GIFContext
*gif
= s
->priv_data
;
191 AVIOContext
*pb
= s
->pb
;
193 flush_packet(s
, NULL
);
194 av_freep(&gif
->prev_pkt
);
200 #define OFFSET(x) offsetof(GIFContext, x)
201 #define ENC AV_OPT_FLAG_ENCODING_PARAM
202 static const AVOption options
[] = {
203 { "loop", "Number of times to loop the output: -1 - no loop, 0 - infinite loop", OFFSET(loop
),
204 AV_OPT_TYPE_INT
, { .i64
= 0 }, -1, 65535, ENC
},
205 { "final_delay", "Force delay (in centiseconds) after the last frame", OFFSET(last_delay
),
206 AV_OPT_TYPE_INT
, { .i64
= -1 }, -1, 65535, ENC
},
210 static const AVClass gif_muxer_class
= {
211 .class_name
= "GIF muxer",
212 .item_name
= av_default_item_name
,
213 .version
= LIBAVUTIL_VERSION_INT
,
217 AVOutputFormat ff_gif_muxer
= {
219 .long_name
= NULL_IF_CONFIG_SMALL("GIF Animation"),
220 .mime_type
= "image/gif",
222 .priv_data_size
= sizeof(GIFContext
),
223 .audio_codec
= AV_CODEC_ID_NONE
,
224 .video_codec
= AV_CODEC_ID_GIF
,
225 .write_header
= gif_write_header
,
226 .write_packet
= gif_write_packet
,
227 .write_trailer
= gif_write_trailer
,
228 .priv_class
= &gif_muxer_class
,
229 .flags
= AVFMT_VARIABLE_FPS
,