yading@11
|
1 /*
|
yading@11
|
2 * Animated GIF muxer
|
yading@11
|
3 * Copyright (c) 2000 Fabrice Bellard
|
yading@11
|
4 *
|
yading@11
|
5 * first version by Francois Revol <revol@free.fr>
|
yading@11
|
6 *
|
yading@11
|
7 * This file is part of FFmpeg.
|
yading@11
|
8 *
|
yading@11
|
9 * FFmpeg is free software; you can redistribute it and/or
|
yading@11
|
10 * modify it under the terms of the GNU Lesser General Public
|
yading@11
|
11 * License as published by the Free Software Foundation; either
|
yading@11
|
12 * version 2.1 of the License, or (at your option) any later version.
|
yading@11
|
13 *
|
yading@11
|
14 * FFmpeg is distributed in the hope that it will be useful,
|
yading@11
|
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
yading@11
|
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
yading@11
|
17 * Lesser General Public License for more details.
|
yading@11
|
18 *
|
yading@11
|
19 * You should have received a copy of the GNU Lesser General Public
|
yading@11
|
20 * License along with FFmpeg; if not, write to the Free Software
|
yading@11
|
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
yading@11
|
22 */
|
yading@11
|
23
|
yading@11
|
24 #include "avformat.h"
|
yading@11
|
25 #include "internal.h"
|
yading@11
|
26 #include "libavutil/avassert.h"
|
yading@11
|
27 #include "libavutil/imgutils.h"
|
yading@11
|
28 #include "libavutil/log.h"
|
yading@11
|
29 #include "libavutil/opt.h"
|
yading@11
|
30
|
yading@11
|
31 static int gif_image_write_header(AVIOContext *pb, int width, int height,
|
yading@11
|
32 int loop_count, uint32_t *palette)
|
yading@11
|
33 {
|
yading@11
|
34 int i;
|
yading@11
|
35
|
yading@11
|
36 avio_write(pb, "GIF", 3);
|
yading@11
|
37 avio_write(pb, "89a", 3);
|
yading@11
|
38 avio_wl16(pb, width);
|
yading@11
|
39 avio_wl16(pb, height);
|
yading@11
|
40
|
yading@11
|
41 if (palette) {
|
yading@11
|
42 avio_w8(pb, 0xf7); /* flags: global clut, 256 entries */
|
yading@11
|
43 avio_w8(pb, 0x1f); /* background color index */
|
yading@11
|
44 avio_w8(pb, 0); /* aspect ratio */
|
yading@11
|
45 for (i = 0; i < 256; i++) {
|
yading@11
|
46 const uint32_t v = palette[i] & 0xffffff;
|
yading@11
|
47 avio_wb24(pb, v);
|
yading@11
|
48 }
|
yading@11
|
49 } else {
|
yading@11
|
50 avio_w8(pb, 0); /* flags */
|
yading@11
|
51 avio_w8(pb, 0); /* background color index */
|
yading@11
|
52 avio_w8(pb, 0); /* aspect ratio */
|
yading@11
|
53 }
|
yading@11
|
54
|
yading@11
|
55 /* "NETSCAPE EXTENSION" for looped animation GIF */
|
yading@11
|
56 avio_w8(pb, 0x21); /* GIF Extension code */
|
yading@11
|
57 avio_w8(pb, 0xff); /* Application Extension Label */
|
yading@11
|
58 avio_w8(pb, 0x0b); /* Length of Application Block */
|
yading@11
|
59 avio_write(pb, "NETSCAPE2.0", sizeof("NETSCAPE2.0") - 1);
|
yading@11
|
60 avio_w8(pb, 0x03); /* Length of Data Sub-Block */
|
yading@11
|
61 avio_w8(pb, 0x01);
|
yading@11
|
62 avio_wl16(pb, (uint16_t)loop_count);
|
yading@11
|
63 avio_w8(pb, 0x00); /* Data Sub-block Terminator */
|
yading@11
|
64
|
yading@11
|
65 return 0;
|
yading@11
|
66 }
|
yading@11
|
67
|
yading@11
|
68 typedef struct {
|
yading@11
|
69 AVClass *class; /** Class for private options. */
|
yading@11
|
70 int loop;
|
yading@11
|
71 int last_delay;
|
yading@11
|
72 AVPacket *prev_pkt;
|
yading@11
|
73 int duration;
|
yading@11
|
74 } GIFContext;
|
yading@11
|
75
|
yading@11
|
76 static int gif_write_header(AVFormatContext *s)
|
yading@11
|
77 {
|
yading@11
|
78 GIFContext *gif = s->priv_data;
|
yading@11
|
79 AVIOContext *pb = s->pb;
|
yading@11
|
80 AVCodecContext *video_enc;
|
yading@11
|
81 int width, height;
|
yading@11
|
82 uint32_t palette[AVPALETTE_COUNT];
|
yading@11
|
83
|
yading@11
|
84 if (s->nb_streams != 1 ||
|
yading@11
|
85 s->streams[0]->codec->codec_type != AVMEDIA_TYPE_VIDEO ||
|
yading@11
|
86 s->streams[0]->codec->codec_id != AV_CODEC_ID_GIF) {
|
yading@11
|
87 av_log(s, AV_LOG_ERROR,
|
yading@11
|
88 "GIF muxer supports only a single video GIF stream.\n");
|
yading@11
|
89 return AVERROR(EINVAL);
|
yading@11
|
90 }
|
yading@11
|
91
|
yading@11
|
92 video_enc = s->streams[0]->codec;
|
yading@11
|
93 width = video_enc->width;
|
yading@11
|
94 height = video_enc->height;
|
yading@11
|
95
|
yading@11
|
96 avpriv_set_pts_info(s->streams[0], 64, 1, 100);
|
yading@11
|
97 if (avpriv_set_systematic_pal2(palette, video_enc->pix_fmt) < 0) {
|
yading@11
|
98 av_assert0(video_enc->pix_fmt == AV_PIX_FMT_PAL8);
|
yading@11
|
99 gif_image_write_header(pb, width, height, gif->loop, NULL);
|
yading@11
|
100 } else {
|
yading@11
|
101 gif_image_write_header(pb, width, height, gif->loop, palette);
|
yading@11
|
102 }
|
yading@11
|
103
|
yading@11
|
104 avio_flush(s->pb);
|
yading@11
|
105 return 0;
|
yading@11
|
106 }
|
yading@11
|
107
|
yading@11
|
108 static int flush_packet(AVFormatContext *s, AVPacket *new)
|
yading@11
|
109 {
|
yading@11
|
110 GIFContext *gif = s->priv_data;
|
yading@11
|
111 int size;
|
yading@11
|
112 AVIOContext *pb = s->pb;
|
yading@11
|
113 uint8_t flags = 0x4, transparent_color_index = 0x1f;
|
yading@11
|
114 const uint32_t *palette;
|
yading@11
|
115 AVPacket *pkt = gif->prev_pkt;
|
yading@11
|
116
|
yading@11
|
117 if (!pkt)
|
yading@11
|
118 return 0;
|
yading@11
|
119
|
yading@11
|
120 /* Mark one colour as transparent if the input palette contains at least
|
yading@11
|
121 * one colour that is more than 50% transparent. */
|
yading@11
|
122 palette = (uint32_t*)av_packet_get_side_data(pkt, AV_PKT_DATA_PALETTE, &size);
|
yading@11
|
123 if (palette && size != AVPALETTE_SIZE) {
|
yading@11
|
124 av_log(s, AV_LOG_ERROR, "Invalid palette extradata\n");
|
yading@11
|
125 return AVERROR_INVALIDDATA;
|
yading@11
|
126 }
|
yading@11
|
127 if (palette) {
|
yading@11
|
128 unsigned i, smallest_alpha = 0xff;
|
yading@11
|
129
|
yading@11
|
130 for (i = 0; i < AVPALETTE_COUNT; i++) {
|
yading@11
|
131 const uint32_t v = palette[i];
|
yading@11
|
132 if (v >> 24 < smallest_alpha) {
|
yading@11
|
133 smallest_alpha = v >> 24;
|
yading@11
|
134 transparent_color_index = i;
|
yading@11
|
135 }
|
yading@11
|
136 }
|
yading@11
|
137 if (smallest_alpha < 128)
|
yading@11
|
138 flags |= 0x1; /* Transparent Color Flag */
|
yading@11
|
139 }
|
yading@11
|
140
|
yading@11
|
141 if (new && new->pts != AV_NOPTS_VALUE)
|
yading@11
|
142 gif->duration = av_clip_uint16(new->pts - gif->prev_pkt->pts);
|
yading@11
|
143 else if (!new && gif->last_delay >= 0)
|
yading@11
|
144 gif->duration = gif->last_delay;
|
yading@11
|
145
|
yading@11
|
146 /* graphic control extension block */
|
yading@11
|
147 avio_w8(pb, 0x21);
|
yading@11
|
148 avio_w8(pb, 0xf9);
|
yading@11
|
149 avio_w8(pb, 0x04); /* block size */
|
yading@11
|
150 avio_w8(pb, flags);
|
yading@11
|
151 avio_wl16(pb, gif->duration);
|
yading@11
|
152 avio_w8(pb, transparent_color_index);
|
yading@11
|
153 avio_w8(pb, 0x00);
|
yading@11
|
154
|
yading@11
|
155 avio_write(pb, pkt->data, pkt->size);
|
yading@11
|
156
|
yading@11
|
157 av_free_packet(gif->prev_pkt);
|
yading@11
|
158 if (new)
|
yading@11
|
159 av_copy_packet(gif->prev_pkt, new);
|
yading@11
|
160
|
yading@11
|
161 return 0;
|
yading@11
|
162 }
|
yading@11
|
163
|
yading@11
|
164 static int gif_write_packet(AVFormatContext *s, AVPacket *pkt)
|
yading@11
|
165 {
|
yading@11
|
166 GIFContext *gif = s->priv_data;
|
yading@11
|
167
|
yading@11
|
168 if (!gif->prev_pkt) {
|
yading@11
|
169 gif->prev_pkt = av_malloc(sizeof(*gif->prev_pkt));
|
yading@11
|
170 if (!gif->prev_pkt)
|
yading@11
|
171 return AVERROR(ENOMEM);
|
yading@11
|
172 return av_copy_packet(gif->prev_pkt, pkt);
|
yading@11
|
173 }
|
yading@11
|
174 return flush_packet(s, pkt);
|
yading@11
|
175 }
|
yading@11
|
176
|
yading@11
|
177 static int gif_write_trailer(AVFormatContext *s)
|
yading@11
|
178 {
|
yading@11
|
179 GIFContext *gif = s->priv_data;
|
yading@11
|
180 AVIOContext *pb = s->pb;
|
yading@11
|
181
|
yading@11
|
182 flush_packet(s, NULL);
|
yading@11
|
183 av_freep(&gif->prev_pkt);
|
yading@11
|
184 avio_w8(pb, 0x3b);
|
yading@11
|
185
|
yading@11
|
186 return 0;
|
yading@11
|
187 }
|
yading@11
|
188
|
yading@11
|
189 #define OFFSET(x) offsetof(GIFContext, x)
|
yading@11
|
190 #define ENC AV_OPT_FLAG_ENCODING_PARAM
|
yading@11
|
191 static const AVOption options[] = {
|
yading@11
|
192 { "loop", "Number of times to loop the output.", OFFSET(loop),
|
yading@11
|
193 AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 65535, ENC },
|
yading@11
|
194 { "final_delay", "Force delay (in ms) after the last frame", OFFSET(last_delay),
|
yading@11
|
195 AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 65535, ENC },
|
yading@11
|
196 { NULL },
|
yading@11
|
197 };
|
yading@11
|
198
|
yading@11
|
199 static const AVClass gif_muxer_class = {
|
yading@11
|
200 .class_name = "GIF muxer",
|
yading@11
|
201 .item_name = av_default_item_name,
|
yading@11
|
202 .version = LIBAVUTIL_VERSION_INT,
|
yading@11
|
203 .option = options,
|
yading@11
|
204 };
|
yading@11
|
205
|
yading@11
|
206 AVOutputFormat ff_gif_muxer = {
|
yading@11
|
207 .name = "gif",
|
yading@11
|
208 .long_name = NULL_IF_CONFIG_SMALL("GIF Animation"),
|
yading@11
|
209 .mime_type = "image/gif",
|
yading@11
|
210 .extensions = "gif",
|
yading@11
|
211 .priv_data_size = sizeof(GIFContext),
|
yading@11
|
212 .audio_codec = AV_CODEC_ID_NONE,
|
yading@11
|
213 .video_codec = AV_CODEC_ID_GIF,
|
yading@11
|
214 .write_header = gif_write_header,
|
yading@11
|
215 .write_packet = gif_write_packet,
|
yading@11
|
216 .write_trailer = gif_write_trailer,
|
yading@11
|
217 .priv_class = &gif_muxer_class,
|
yading@11
|
218 .flags = AVFMT_VARIABLE_FPS,
|
yading@11
|
219 };
|