FFmpeg  4.3.9
gif.c
Go to the documentation of this file.
1 /*
2  * Animated GIF muxer
3  * Copyright (c) 2000 Fabrice Bellard
4  *
5  * first version by Francois Revol <revol@free.fr>
6  *
7  * This file is part of FFmpeg.
8  *
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.
13  *
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.
18  *
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
22  */
23 
24 #include "avformat.h"
25 #include "internal.h"
26 #include "libavutil/avassert.h"
27 #include "libavutil/imgutils.h"
28 #include "libavutil/log.h"
29 #include "libavutil/opt.h"
30 #include "libavcodec/bytestream.h"
31 #include "libavcodec/gif.h"
32 
33 typedef struct GIFContext {
34  AVClass *class;
35  int loop;
37  int duration;
39  int have_end;
41 } GIFContext;
42 
44 {
45  if (s->nb_streams != 1 ||
49  "GIF muxer supports only a single video GIF stream.\n");
50  return AVERROR(EINVAL);
51  }
52 
53  avpriv_set_pts_info(s->streams[0], 64, 1, 100);
54 
55  return 0;
56 }
57 
59 {
60  GetByteContext gb;
61  int x;
62 
63  bytestream2_init(&gb, data, size);
64 
65  while (bytestream2_get_bytes_left(&gb) > 0) {
66  x = bytestream2_get_byte(&gb);
67  if (x != GIF_EXTENSION_INTRODUCER)
68  return 0;
69 
70  x = bytestream2_get_byte(&gb);
71  while (x != GIF_GCE_EXT_LABEL && bytestream2_get_bytes_left(&gb) > 0) {
72  int block_size = bytestream2_get_byte(&gb);
73  if (!block_size)
74  break;
75  bytestream2_skip(&gb, block_size);
76  }
77 
78  if (x == GIF_GCE_EXT_LABEL)
79  return bytestream2_tell(&gb) + 2;
80  }
81 
82  return 0;
83 }
84 
85 static int gif_get_delay(GIFContext *gif, AVPacket *prev, AVPacket *new)
86 {
87  if (new && new->pts != AV_NOPTS_VALUE)
88  gif->duration = av_clip_uint16(new->pts - prev->pts);
89  else if (!new && gif->last_delay >= 0)
90  gif->duration = gif->last_delay;
91 
92  return gif->duration;
93 }
94 
96 {
97  GIFContext *gif = s->priv_data;
98  AVIOContext *pb = s->pb;
99  AVPacket *pkt = gif->prev_pkt;
100 
101  if (!gif->prev_pkt) {
102  gif->prev_pkt = av_packet_alloc();
103  if (!gif->prev_pkt)
104  return AVERROR(ENOMEM);
105  return av_packet_ref(gif->prev_pkt, new_pkt);
106  }
107 
108  gif->last_pos = avio_tell(pb);
109  if (pkt->size > 0)
110  gif->have_end = pkt->data[pkt->size - 1] == GIF_TRAILER;
111 
112  if (!gif->last_pos) {
113  int delay_pos;
114  int off = 13;
115 
116  if (pkt->size < 13)
117  return AVERROR(EINVAL);
118 
119  if (pkt->data[10] & 0x80)
120  off += 3 * (1 << ((pkt->data[10] & 0x07) + 1));
121 
122  if (pkt->size < off + 2)
123  return AVERROR(EINVAL);
124 
125  avio_write(pb, pkt->data, off);
126 
127  if (pkt->data[off] == GIF_EXTENSION_INTRODUCER && pkt->data[off + 1] == 0xff)
128  off += 19;
129 
130  if (pkt->size <= off)
131  return AVERROR(EINVAL);
132 
133  /* "NETSCAPE EXTENSION" for looped animation GIF */
134  if (gif->loop >= 0) {
135  avio_w8(pb, GIF_EXTENSION_INTRODUCER); /* GIF Extension code */
136  avio_w8(pb, GIF_APP_EXT_LABEL); /* Application Extension Label */
137  avio_w8(pb, 0x0b); /* Length of Application Block */
138  avio_write(pb, "NETSCAPE2.0", sizeof("NETSCAPE2.0") - 1);
139  avio_w8(pb, 0x03); /* Length of Data Sub-Block */
140  avio_w8(pb, 0x01);
141  avio_wl16(pb, (uint16_t)gif->loop);
142  avio_w8(pb, 0x00); /* Data Sub-block Terminator */
143  }
144 
145  delay_pos = gif_parse_packet(s, pkt->data + off, pkt->size - off);
146  if (delay_pos > 0 && delay_pos < pkt->size - off - 2) {
147  avio_write(pb, pkt->data + off, delay_pos);
148  avio_wl16(pb, gif_get_delay(gif, pkt, new_pkt));
149  avio_write(pb, pkt->data + off + delay_pos + 2, pkt->size - off - delay_pos - 2);
150  } else {
151  avio_write(pb, pkt->data + off, pkt->size - off);
152  }
153  } else {
154  int delay_pos = gif_parse_packet(s, pkt->data, pkt->size);
155 
156  if (delay_pos > 0 && delay_pos < pkt->size - 2) {
157  avio_write(pb, pkt->data, delay_pos);
158  avio_wl16(pb, gif_get_delay(gif, pkt, new_pkt));
159  avio_write(pb, pkt->data + delay_pos + 2, pkt->size - delay_pos - 2);
160  } else {
161  avio_write(pb, pkt->data, pkt->size);
162  }
163  }
164 
166  if (new_pkt)
167  return av_packet_ref(gif->prev_pkt, new_pkt);
168 
169  return 0;
170 }
171 
173 {
174  GIFContext *gif = s->priv_data;
175  AVIOContext *pb = s->pb;
176 
177  if (!gif->prev_pkt)
178  return AVERROR(EINVAL);
179 
181 
182  if (!gif->have_end)
183  avio_w8(pb, GIF_TRAILER);
184  av_packet_free(&gif->prev_pkt);
185 
186  return 0;
187 }
188 
189 #define OFFSET(x) offsetof(GIFContext, x)
190 #define ENC AV_OPT_FLAG_ENCODING_PARAM
191 static const AVOption options[] = {
192  { "loop", "Number of times to loop the output: -1 - no loop, 0 - infinite loop", OFFSET(loop),
193  AV_OPT_TYPE_INT, { .i64 = 0 }, -1, 65535, ENC },
194  { "final_delay", "Force delay (in centiseconds) after the last frame", OFFSET(last_delay),
195  AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 65535, ENC },
196  { NULL },
197 };
198 
199 static const AVClass gif_muxer_class = {
200  .class_name = "GIF muxer",
201  .item_name = av_default_item_name,
202  .version = LIBAVUTIL_VERSION_INT,
203  .option = options,
204 };
205 
207  .name = "gif",
208  .long_name = NULL_IF_CONFIG_SMALL("CompuServe Graphics Interchange Format (GIF)"),
209  .mime_type = "image/gif",
210  .extensions = "gif",
211  .priv_data_size = sizeof(GIFContext),
212  .audio_codec = AV_CODEC_ID_NONE,
213  .video_codec = AV_CODEC_ID_GIF,
217  .priv_class = &gif_muxer_class,
219 };
static void write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int unqueue)
Definition: ffmpeg.c:703
#define NULL
Definition: coverity.c:32
int64_t last_pos
Definition: gif.c:38
void avio_wl16(AVIOContext *s, unsigned int val)
Definition: aviobuf.c:447
Bytestream IO Context.
Definition: avio.h:161
int size
AVOption.
Definition: opt.h:246
#define OFFSET(x)
Definition: gif.c:189
misc image utilities
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
void avpriv_set_pts_info(AVStream *s, int pts_wrap_bits, unsigned int pts_num, unsigned int pts_den)
Set the time base and wrapping info for a given stream.
Definition: utils.c:4948
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: codec_par.h:60
int have_end
Definition: gif.c:39
int size
Definition: packet.h:356
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:235
#define GIF_GCE_EXT_LABEL
Definition: gif.h:45
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition: bytestream.h:133
static int gif_write_header(AVFormatContext *s)
Definition: gif.c:43
static const AVClass gif_muxer_class
Definition: gif.c:199
#define ENC
Definition: gif.c:190
static AVPacket pkt
AVOutputFormat ff_gif_muxer
Definition: gif.c:206
Format I/O context.
Definition: avformat.h:1351
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
Definition: log.h:72
void av_packet_free(AVPacket **pkt)
Free the packet, if the packet is reference counted, it will be unreferenced first.
Definition: avpacket.c:64
uint8_t
AVOptions.
AVStream ** streams
A list of all streams in the file.
Definition: avformat.h:1419
const char data[16]
Definition: mxf.c:91
uint8_t * data
Definition: packet.h:355
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition: avio.h:557
void avio_write(AVIOContext *s, const unsigned char *buf, int size)
Definition: aviobuf.c:213
int flags
Definition: gif.c:52
#define av_log(a,...)
int av_packet_ref(AVPacket *dst, const AVPacket *src)
Setup a new reference to the data described by a given packet.
Definition: avpacket.c:614
static av_always_inline int bytestream2_get_bytes_left(GetByteContext *g)
Definition: bytestream.h:154
int loop
Definition: gif.c:35
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
#define AVERROR(e)
Definition: error.h:43
static av_always_inline void bytestream2_skip(GetByteContext *g, unsigned int size)
Definition: bytestream.h:164
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:188
Definition: gif.c:46
enum AVMediaType codec_type
General type of the encoded data.
Definition: codec_par.h:56
simple assert() macros that are a bit more flexible than ISO C assert().
AVPacket * prev_pkt
Definition: gif.c:40
unsigned int nb_streams
Number of elements in AVFormatContext.streams.
Definition: avformat.h:1407
static int write_trailer(AVFormatContext *s1)
Definition: v4l2enc.c:98
#define GIF_APP_EXT_LABEL
Definition: gif.h:47
const char * name
Definition: avformat.h:500
#define s(width, name)
Definition: cbs_vp9.c:257
int duration
Definition: gif.c:37
#define GIF_EXTENSION_INTRODUCER
Definition: gif.h:43
static av_always_inline int bytestream2_tell(GetByteContext *g)
Definition: bytestream.h:188
static int gif_write_trailer(AVFormatContext *s)
Definition: gif.c:172
AVIOContext * pb
I/O context.
Definition: avformat.h:1393
static int gif_get_delay(GIFContext *gif, AVPacket *prev, AVPacket *new)
Definition: gif.c:85
static const AVOption options[]
Definition: gif.c:191
void avio_w8(AVIOContext *s, int b)
Definition: aviobuf.c:191
GIF format definitions.
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
Definition: avpacket.c:605
long long int64_t
Definition: coverity.c:34
int last_delay
Definition: gif.c:36
Describe the class of an AVClass context structure.
Definition: log.h:67
static int gif_parse_packet(AVFormatContext *s, uint8_t *data, int size)
Definition: gif.c:58
#define GIF_TRAILER
Definition: gif.h:42
Main libavformat public API header.
#define AVFMT_VARIABLE_FPS
Format allows variable fps.
Definition: avformat.h:465
void * priv_data
Format private data.
Definition: avformat.h:1379
AVPacket * av_packet_alloc(void)
Allocate an AVPacket and set its fields to default values.
Definition: avpacket.c:53
static void write_header(FFV1Context *f)
Definition: ffv1enc.c:346
static int gif_write_packet(AVFormatContext *s, AVPacket *new_pkt)
Definition: gif.c:95
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:1023
This structure stores compressed data.
Definition: packet.h:332
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: packet.h:348
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:248