FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/gif.c
Date: 2021-09-23 20:34:37
Exec Total Coverage
Lines: 219 289 75.8%
Branches: 131 218 60.1%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2000 Fabrice Bellard
3 * Copyright (c) 2002 Francois Revol
4 * Copyright (c) 2006 Baptiste Coudurier
5 * Copyright (c) 2018 Bjorn Roche
6 * Copyright (c) 2018 Paul B Mahol
7 *
8 * first version by Francois Revol <revol@free.fr>
9 *
10 * This file is part of FFmpeg.
11 *
12 * FFmpeg is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
16 *
17 * FFmpeg is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
21 *
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with FFmpeg; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 */
26
27 /**
28 * @file
29 * GIF encoder
30 * @see http://www.w3.org/Graphics/GIF/spec-gif89a.txt
31 */
32
33 #define BITSTREAM_WRITER_LE
34 #include "libavutil/opt.h"
35 #include "libavutil/imgutils.h"
36 #include "avcodec.h"
37 #include "bytestream.h"
38 #include "encode.h"
39 #include "internal.h"
40 #include "lzw.h"
41 #include "gif.h"
42
43 #include "put_bits.h"
44
45 #define DEFAULT_TRANSPARENCY_INDEX 0x1f
46
47 typedef struct GIFContext {
48 const AVClass *class;
49 LZWState *lzw;
50 uint8_t *buf;
51 uint8_t *shrunk_buf;
52 int buf_size;
53 AVFrame *last_frame;
54 int flags;
55 int image;
56 int use_global_palette;
57 uint32_t palette[AVPALETTE_COUNT]; ///< local reference palette for !pal8
58 int palette_loaded;
59 int transparent_index;
60 uint8_t *tmpl; ///< temporary line buffer
61 } GIFContext;
62
63 enum {
64 GF_OFFSETTING = 1<<0,
65 GF_TRANSDIFF = 1<<1,
66 };
67
68 1 static void shrink_palette(const uint32_t *src, uint8_t *map,
69 uint32_t *dst, size_t *palette_count)
70 {
71 1 size_t colors_seen = 0;
72
73
2/2
✓ Branch 0 taken 256 times.
✓ Branch 1 taken 1 times.
257 for (size_t i = 0; i < AVPALETTE_COUNT; i++) {
74 256 int seen = 0;
75
2/2
✓ Branch 0 taken 32640 times.
✓ Branch 1 taken 256 times.
32896 for (size_t c = 0; c < colors_seen; c++) {
76
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32640 times.
32640 if (src[i] == dst[c]) {
77 seen = 1;
78 break;
79 }
80 }
81
1/2
✓ Branch 0 taken 256 times.
✗ Branch 1 not taken.
256 if (!seen) {
82 256 dst[colors_seen] = src[i];
83 256 map[i] = colors_seen;
84 256 colors_seen++;
85 }
86 }
87
88 1 *palette_count = colors_seen;
89 1 }
90
91 1 static void remap_frame_to_palette(const uint8_t *src, int src_linesize,
92 uint8_t *dst, int dst_linesize,
93 int w, int h, uint8_t *map)
94 {
95
2/2
✓ Branch 0 taken 217 times.
✓ Branch 1 taken 1 times.
218 for (int i = 0; i < h; i++)
96
2/2
✓ Branch 0 taken 47089 times.
✓ Branch 1 taken 217 times.
47306 for (int j = 0; j < w; j++)
97 47089 dst[i * dst_linesize + j] = map[src[i * src_linesize + j]];
98 1 }
99
100 1063 static int is_image_translucent(AVCodecContext *avctx,
101 const uint8_t *buf, const int linesize)
102 {
103 1063 GIFContext *s = avctx->priv_data;
104 1063 int trans = s->transparent_index;
105
106
1/2
✓ Branch 0 taken 1063 times.
✗ Branch 1 not taken.
1063 if (trans < 0)
107 1063 return 0;
108
109 for (int y = 0; y < avctx->height; y++) {
110 for (int x = 0; x < avctx->width; x++) {
111 if (buf[x] == trans) {
112 return 1;
113 }
114 }
115 buf += linesize;
116 }
117
118 return 0;
119 }
120
121 39 static int get_palette_transparency_index(const uint32_t *palette)
122 {
123 39 int transparent_color_index = -1;
124 39 unsigned i, smallest_alpha = 0xff;
125
126
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 9 times.
39 if (!palette)
127 30 return -1;
128
129
2/2
✓ Branch 0 taken 2304 times.
✓ Branch 1 taken 9 times.
2313 for (i = 0; i < AVPALETTE_COUNT; i++) {
130 2304 const uint32_t v = palette[i];
131
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2302 times.
2304 if (v >> 24 < smallest_alpha) {
132 2 smallest_alpha = v >> 24;
133 2 transparent_color_index = i;
134 }
135 }
136
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 7 times.
9 return smallest_alpha < 128 ? transparent_color_index : -1;
137 }
138
139 1056 static int pick_palette_entry(const uint8_t *buf, int linesize, int w, int h)
140 {
141 1056 int histogram[AVPALETTE_COUNT] = {0};
142 int x, y, i;
143
144
2/2
✓ Branch 0 taken 32487 times.
✓ Branch 1 taken 1056 times.
33543 for (y = 0; y < h; y++) {
145
2/2
✓ Branch 0 taken 3157775 times.
✓ Branch 1 taken 32487 times.
3190262 for (x = 0; x < w; x++)
146 3157775 histogram[buf[x]]++;
147 32487 buf += linesize;
148 }
149
2/2
✓ Branch 0 taken 7288 times.
✓ Branch 1 taken 24 times.
7312 for (i = 0; i < FF_ARRAY_ELEMS(histogram); i++)
150
2/2
✓ Branch 0 taken 1032 times.
✓ Branch 1 taken 6256 times.
7288 if (!histogram[i])
151 1032 return i;
152 24 return -1;
153 }
154
155 static void gif_crop_translucent(AVCodecContext *avctx,
156 const uint8_t *buf, const int linesize,
157 int *width, int *height,
158 int *x_start, int *y_start)
159 {
160 GIFContext *s = avctx->priv_data;
161 int trans = s->transparent_index;
162
163 /* Crop image */
164 if ((s->flags & GF_OFFSETTING) && trans >= 0) {
165 const int w = avctx->width;
166 const int h = avctx->height;
167 int x_end = w - 1,
168 y_end = h - 1;
169
170 // crop top
171 while (*y_start < y_end) {
172 int is_trans = 1;
173 for (int i = 0; i < w; i++) {
174 if (buf[linesize * *y_start + i] != trans) {
175 is_trans = 0;
176 break;
177 }
178 }
179
180 if (!is_trans)
181 break;
182 (*y_start)++;
183 }
184
185 // crop bottom
186 while (y_end > *y_start) {
187 int is_trans = 1;
188 for (int i = 0; i < w; i++) {
189 if (buf[linesize * y_end + i] != trans) {
190 is_trans = 0;
191 break;
192 }
193 }
194 if (!is_trans)
195 break;
196 y_end--;
197 }
198
199 // crop left
200 while (*x_start < x_end) {
201 int is_trans = 1;
202 for (int i = *y_start; i < y_end; i++) {
203 if (buf[linesize * i + *x_start] != trans) {
204 is_trans = 0;
205 break;
206 }
207 }
208 if (!is_trans)
209 break;
210 (*x_start)++;
211 }
212
213 // crop right
214 while (x_end > *x_start) {
215 int is_trans = 1;
216 for (int i = *y_start; i < y_end; i++) {
217 if (buf[linesize * i + x_end] != trans) {
218 is_trans = 0;
219 break;
220 }
221 }
222 if (!is_trans)
223 break;
224 x_end--;
225 }
226
227 *height = y_end + 1 - *y_start;
228 *width = x_end + 1 - *x_start;
229 av_log(avctx, AV_LOG_DEBUG,"%dx%d image at pos (%d;%d) [area:%dx%d]\n",
230 *width, *height, *x_start, *y_start, avctx->width, avctx->height);
231 }
232 }
233
234 1063 static void gif_crop_opaque(AVCodecContext *avctx,
235 const uint32_t *palette,
236 const uint8_t *buf, const int linesize,
237 int *width, int *height, int *x_start, int *y_start)
238 {
239 1063 GIFContext *s = avctx->priv_data;
240
241 /* Crop image */
242
4/6
✓ Branch 0 taken 1063 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1056 times.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 1056 times.
✗ Branch 5 not taken.
1063 if ((s->flags & GF_OFFSETTING) && s->last_frame && !palette) {
243 1056 const uint8_t *ref = s->last_frame->data[0];
244 1056 const int ref_linesize = s->last_frame->linesize[0];
245 1056 int x_end = avctx->width - 1,
246 1056 y_end = avctx->height - 1;
247
248 /* skip common lines */
249
1/2
✓ Branch 0 taken 100704 times.
✗ Branch 1 not taken.
100704 while (*y_start < y_end) {
250
2/2
✓ Branch 0 taken 1056 times.
✓ Branch 1 taken 99648 times.
100704 if (memcmp(ref + *y_start*ref_linesize, buf + *y_start*linesize, *width))
251 1056 break;
252 99648 (*y_start)++;
253 }
254
1/2
✓ Branch 0 taken 99777 times.
✗ Branch 1 not taken.
99777 while (y_end > *y_start) {
255
2/2
✓ Branch 0 taken 1056 times.
✓ Branch 1 taken 98721 times.
99777 if (memcmp(ref + y_end*ref_linesize, buf + y_end*linesize, *width))
256 1056 break;
257 98721 y_end--;
258 }
259 1056 *height = y_end + 1 - *y_start;
260
261 /* skip common columns */
262
1/2
✓ Branch 0 taken 96923 times.
✗ Branch 1 not taken.
96923 while (*x_start < x_end) {
263 96923 int same_column = 1;
264
2/2
✓ Branch 0 taken 2402634 times.
✓ Branch 1 taken 95867 times.
2498501 for (int y = *y_start; y <= y_end; y++) {
265
2/2
✓ Branch 0 taken 1056 times.
✓ Branch 1 taken 2401578 times.
2402634 if (ref[y*ref_linesize + *x_start] != buf[y*linesize + *x_start]) {
266 1056 same_column = 0;
267 1056 break;
268 }
269 }
270
2/2
✓ Branch 0 taken 1056 times.
✓ Branch 1 taken 95867 times.
96923 if (!same_column)
271 1056 break;
272 95867 (*x_start)++;
273 }
274
1/2
✓ Branch 0 taken 104460 times.
✗ Branch 1 not taken.
104460 while (x_end > *x_start) {
275 104460 int same_column = 1;
276
2/2
✓ Branch 0 taken 2442709 times.
✓ Branch 1 taken 103404 times.
2546113 for (int y = *y_start; y <= y_end; y++) {
277
2/2
✓ Branch 0 taken 1056 times.
✓ Branch 1 taken 2441653 times.
2442709 if (ref[y*ref_linesize + x_end] != buf[y*linesize + x_end]) {
278 1056 same_column = 0;
279 1056 break;
280 }
281 }
282
2/2
✓ Branch 0 taken 1056 times.
✓ Branch 1 taken 103404 times.
104460 if (!same_column)
283 1056 break;
284 103404 x_end--;
285 }
286 1056 *width = x_end + 1 - *x_start;
287
288 1056 av_log(avctx, AV_LOG_DEBUG,"%dx%d image at pos (%d;%d) [area:%dx%d]\n",
289 *width, *height, *x_start, *y_start, avctx->width, avctx->height);
290 }
291 1063 }
292
293 1063 static int gif_image_write_image(AVCodecContext *avctx,
294 uint8_t **bytestream, uint8_t *end,
295 const uint32_t *palette,
296 const uint8_t *buf, const int linesize,
297 AVPacket *pkt)
298 {
299 1063 GIFContext *s = avctx->priv_data;
300 1063 int disposal, len = 0, height = avctx->height, width = avctx->width, x, y;
301 1063 int x_start = 0, y_start = 0, trans = s->transparent_index;
302
4/6
✓ Branch 0 taken 1063 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1056 times.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 1056 times.
✗ Branch 5 not taken.
1063 int bcid = -1, honor_transparency = (s->flags & GF_TRANSDIFF) && s->last_frame && !palette;
303 const uint8_t *ptr;
304 uint32_t shrunk_palette[AVPALETTE_COUNT];
305 1063 uint8_t map[AVPALETTE_COUNT] = { 0 };
306 1063 size_t shrunk_palette_count = 0;
307
308 /*
309 * We memset to 0xff instead of 0x00 so that the transparency detection
310 * doesn't pick anything after the palette entries as the transparency
311 * index, and because GIF89a requires us to always write a power-of-2
312 * number of palette entries.
313 */
314 1063 memset(shrunk_palette, 0xff, AVPALETTE_SIZE);
315
316
2/4
✓ Branch 0 taken 1063 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1063 times.
1063 if (!s->image && is_image_translucent(avctx, buf, linesize)) {
317 gif_crop_translucent(avctx, buf, linesize, &width, &height, &x_start, &y_start);
318 honor_transparency = 0;
319 disposal = GCE_DISPOSAL_BACKGROUND;
320 } else {
321 1063 gif_crop_opaque(avctx, palette, buf, linesize, &width, &height, &x_start, &y_start);
322 1063 disposal = GCE_DISPOSAL_INPLACE;
323 }
324
325
3/4
✓ Branch 0 taken 1063 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 1056 times.
1063 if (s->image || !avctx->frame_number) { /* GIF header */
326
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1 times.
7 const uint32_t *global_palette = palette ? palette : s->palette;
327 7 const AVRational sar = avctx->sample_aspect_ratio;
328 7 int64_t aspect = 0;
329
330
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
7 if (sar.num > 0 && sar.den > 0) {
331 aspect = sar.num * 64LL / sar.den - 15;
332 if (aspect < 0 || aspect > 255)
333 aspect = 0;
334 }
335
336 7 bytestream_put_buffer(bytestream, gif89a_sig, sizeof(gif89a_sig));
337 7 bytestream_put_le16(bytestream, avctx->width);
338 7 bytestream_put_le16(bytestream, avctx->height);
339
340 7 bcid = get_palette_transparency_index(global_palette);
341
342
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 bytestream_put_byte(bytestream, ((uint8_t) s->use_global_palette << 7) | 0x70 | (s->use_global_palette ? 7 : 0)); /* flags: global clut, 256 entries */
343
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 5 times.
7 bytestream_put_byte(bytestream, bcid < 0 ? DEFAULT_TRANSPARENCY_INDEX : bcid); /* background color index */
344 7 bytestream_put_byte(bytestream, aspect);
345
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (s->use_global_palette) {
346
2/2
✓ Branch 0 taken 1792 times.
✓ Branch 1 taken 7 times.
1799 for (int i = 0; i < 256; i++) {
347 1792 const uint32_t v = global_palette[i] & 0xffffff;
348 1792 bytestream_put_be24(bytestream, v);
349 }
350 }
351 }
352
353
3/4
✓ Branch 0 taken 1056 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 1056 times.
✗ Branch 3 not taken.
1063 if (honor_transparency && trans < 0) {
354 1056 trans = pick_palette_entry(buf + y_start*linesize + x_start,
355 linesize, width, height);
356
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 1032 times.
1056 if (trans < 0) // TODO, patch welcome
357 24 av_log(avctx, AV_LOG_DEBUG, "No available color, can not use transparency\n");
358 }
359
360
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 1032 times.
1063 if (trans < 0)
361 31 honor_transparency = 0;
362
363
3/4
✓ Branch 0 taken 1062 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1062 times.
1063 if (palette || !s->use_global_palette) {
364
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 const uint32_t *pal = palette ? palette : s->palette;
365 1 shrink_palette(pal, map, shrunk_palette, &shrunk_palette_count);
366 }
367
368
3/4
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 1032 times.
✓ Branch 2 taken 31 times.
✗ Branch 3 not taken.
1063 bcid = honor_transparency || disposal == GCE_DISPOSAL_BACKGROUND ? trans : get_palette_transparency_index(palette);
369
370 /* graphic control extension */
371 1063 bytestream_put_byte(bytestream, GIF_EXTENSION_INTRODUCER);
372 1063 bytestream_put_byte(bytestream, GIF_GCE_EXT_LABEL);
373 1063 bytestream_put_byte(bytestream, 0x04); /* block size */
374 1063 bytestream_put_byte(bytestream, disposal<<2 | (bcid >= 0));
375 1063 bytestream_put_le16(bytestream, 5); // default delay
376
3/4
✓ Branch 0 taken 1032 times.
✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1032 times.
1063 bytestream_put_byte(bytestream, bcid < 0 ? DEFAULT_TRANSPARENCY_INDEX : (shrunk_palette_count ? map[bcid] : bcid));
377 1063 bytestream_put_byte(bytestream, 0x00);
378
379 /* image block */
380 1063 bytestream_put_byte(bytestream, GIF_IMAGE_SEPARATOR);
381 1063 bytestream_put_le16(bytestream, x_start);
382 1063 bytestream_put_le16(bytestream, y_start);
383 1063 bytestream_put_le16(bytestream, width);
384 1063 bytestream_put_le16(bytestream, height);
385
386
3/4
✓ Branch 0 taken 1062 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1062 times.
1064 if (palette || !s->use_global_palette) {
387 1 unsigned pow2_count = av_log2(shrunk_palette_count - 1);
388 unsigned i;
389
390 1 bytestream_put_byte(bytestream, 1<<7 | pow2_count); /* flags */
391
2/2
✓ Branch 0 taken 256 times.
✓ Branch 1 taken 1 times.
257 for (i = 0; i < 1 << (pow2_count + 1); i++) {
392 256 const uint32_t v = shrunk_palette[i];
393 256 bytestream_put_be24(bytestream, v);
394 }
395 } else {
396 1062 bytestream_put_byte(bytestream, 0x00); /* flags */
397 }
398
399 1063 bytestream_put_byte(bytestream, 0x08);
400
401 1063 ff_lzw_encode_init(s->lzw, s->buf, s->buf_size,
402 12, FF_LZW_GIF, 1);
403
404
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1062 times.
1063 if (shrunk_palette_count) {
405
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!s->shrunk_buf) {
406 1 s->shrunk_buf = av_malloc(avctx->height * linesize);
407
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!s->shrunk_buf) {
408 av_log(avctx, AV_LOG_ERROR, "Could not allocated remapped frame buffer.\n");
409 return AVERROR(ENOMEM);
410 }
411 }
412 1 remap_frame_to_palette(buf, linesize, s->shrunk_buf, linesize, avctx->width, avctx->height, map);
413 1 ptr = s->shrunk_buf + y_start*linesize + x_start;
414 } else {
415 1062 ptr = buf + y_start*linesize + x_start;
416 }
417
2/2
✓ Branch 0 taken 1032 times.
✓ Branch 1 taken 31 times.
1063 if (honor_transparency) {
418 1032 const int ref_linesize = s->last_frame->linesize[0];
419 1032 const uint8_t *ref = s->last_frame->data[0] + y_start*ref_linesize + x_start;
420
421
2/2
✓ Branch 0 taken 25575 times.
✓ Branch 1 taken 1032 times.
26607 for (y = 0; y < height; y++) {
422 25575 memcpy(s->tmpl, ptr, width);
423
2/2
✓ Branch 0 taken 724751 times.
✓ Branch 1 taken 25575 times.
750326 for (x = 0; x < width; x++)
424
2/2
✓ Branch 0 taken 367271 times.
✓ Branch 1 taken 357480 times.
724751 if (ref[x] == ptr[x])
425 367271 s->tmpl[x] = trans;
426 25575 len += ff_lzw_encode(s->lzw, s->tmpl, width);
427 25575 ptr += linesize;
428 25575 ref += ref_linesize;
429 }
430 } else {
431
2/2
✓ Branch 0 taken 8502 times.
✓ Branch 1 taken 31 times.
8533 for (y = 0; y < height; y++) {
432 8502 len += ff_lzw_encode(s->lzw, ptr, width);
433 8502 ptr += linesize;
434 }
435 }
436 1063 len += ff_lzw_encode_flush(s->lzw);
437
438 1063 ptr = s->buf;
439
2/2
✓ Branch 0 taken 9251 times.
✓ Branch 1 taken 1063 times.
10314 while (len > 0) {
440 9251 int size = FFMIN(255, len);
441 9251 bytestream_put_byte(bytestream, size);
442
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9251 times.
9251 if (end - *bytestream < size)
443 return -1;
444 9251 bytestream_put_buffer(bytestream, ptr, size);
445 9251 ptr += size;
446 9251 len -= size;
447 }
448 1063 bytestream_put_byte(bytestream, 0x00); /* end of image block */
449 1063 return 0;
450 }
451
452 7 static av_cold int gif_encode_init(AVCodecContext *avctx)
453 {
454 7 GIFContext *s = avctx->priv_data;
455
456
2/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
7 if (avctx->width > 65535 || avctx->height > 65535) {
457 av_log(avctx, AV_LOG_ERROR, "GIF does not support resolutions above 65535x65535\n");
458 return AVERROR(EINVAL);
459 }
460
461 7 s->transparent_index = -1;
462
463 7 s->lzw = av_mallocz(ff_lzw_encode_state_size);
464 7 s->buf_size = avctx->width*avctx->height*2 + 1000;
465 7 s->buf = av_malloc(s->buf_size);
466 7 s->tmpl = av_malloc(avctx->width);
467
3/6
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 7 times.
7 if (!s->tmpl || !s->buf || !s->lzw)
468 return AVERROR(ENOMEM);
469
470
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 6 times.
7 if (avpriv_set_systematic_pal2(s->palette, avctx->pix_fmt) < 0)
471
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 av_assert0(avctx->pix_fmt == AV_PIX_FMT_PAL8);
472
473 7 return 0;
474 }
475
476 1063 static int gif_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
477 const AVFrame *pict, int *got_packet)
478 {
479 1063 GIFContext *s = avctx->priv_data;
480 uint8_t *outbuf_ptr, *end;
481 1063 const uint32_t *palette = NULL;
482 int ret;
483
484
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1063 times.
1063 if ((ret = ff_alloc_packet(avctx, pkt, avctx->width*avctx->height*7/5 + AV_INPUT_BUFFER_MIN_SIZE)) < 0)
485 return ret;
486 1063 outbuf_ptr = pkt->data;
487 1063 end = pkt->data + pkt->size;
488
489
2/2
✓ Branch 0 taken 173 times.
✓ Branch 1 taken 890 times.
1063 if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
490 173 palette = (uint32_t*)pict->data[1];
491
492
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 172 times.
173 if (!s->palette_loaded) {
493 1 memcpy(s->palette, palette, AVPALETTE_SIZE);
494 1 s->transparent_index = get_palette_transparency_index(palette);
495 1 s->palette_loaded = 1;
496
1/2
✓ Branch 0 taken 172 times.
✗ Branch 1 not taken.
172 } else if (!memcmp(s->palette, palette, AVPALETTE_SIZE)) {
497 172 palette = NULL;
498 }
499 }
500
501 1063 gif_image_write_image(avctx, &outbuf_ptr, end, palette,
502 1063 pict->data[0], pict->linesize[0], pkt);
503
3/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1056 times.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
1063 if (!s->last_frame && !s->image) {
504 7 s->last_frame = av_frame_alloc();
505
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (!s->last_frame)
506 return AVERROR(ENOMEM);
507 }
508
509
1/2
✓ Branch 0 taken 1063 times.
✗ Branch 1 not taken.
1063 if (!s->image) {
510 1063 av_frame_unref(s->last_frame);
511 1063 ret = av_frame_ref(s->last_frame, (AVFrame*)pict);
512
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1063 times.
1063 if (ret < 0)
513 return ret;
514 }
515
516 1063 pkt->size = outbuf_ptr - pkt->data;
517
3/4
✓ Branch 0 taken 1063 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 1056 times.
1063 if (s->image || !avctx->frame_number)
518 7 pkt->flags |= AV_PKT_FLAG_KEY;
519 1063 *got_packet = 1;
520
521 1063 return 0;
522 }
523
524 7 static int gif_encode_close(AVCodecContext *avctx)
525 {
526 7 GIFContext *s = avctx->priv_data;
527
528 7 av_freep(&s->lzw);
529 7 av_freep(&s->buf);
530 7 av_freep(&s->shrunk_buf);
531 7 s->buf_size = 0;
532 7 av_frame_free(&s->last_frame);
533 7 av_freep(&s->tmpl);
534 7 return 0;
535 }
536
537 #define OFFSET(x) offsetof(GIFContext, x)
538 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
539 static const AVOption gif_options[] = {
540 { "gifflags", "set GIF flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = GF_OFFSETTING|GF_TRANSDIFF}, 0, INT_MAX, FLAGS, "flags" },
541 { "offsetting", "enable picture offsetting", 0, AV_OPT_TYPE_CONST, {.i64=GF_OFFSETTING}, INT_MIN, INT_MAX, FLAGS, "flags" },
542 { "transdiff", "enable transparency detection between frames", 0, AV_OPT_TYPE_CONST, {.i64=GF_TRANSDIFF}, INT_MIN, INT_MAX, FLAGS, "flags" },
543 { "gifimage", "enable encoding only images per frame", OFFSET(image), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
544 { "global_palette", "write a palette to the global gif header where feasible", OFFSET(use_global_palette), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS },
545 { NULL }
546 };
547
548 static const AVClass gif_class = {
549 .class_name = "GIF encoder",
550 .item_name = av_default_item_name,
551 .option = gif_options,
552 .version = LIBAVUTIL_VERSION_INT,
553 };
554
555 const AVCodec ff_gif_encoder = {
556 .name = "gif",
557 .long_name = NULL_IF_CONFIG_SMALL("GIF (Graphics Interchange Format)"),
558 .type = AVMEDIA_TYPE_VIDEO,
559 .id = AV_CODEC_ID_GIF,
560 .priv_data_size = sizeof(GIFContext),
561 .init = gif_encode_init,
562 .encode2 = gif_encode_frame,
563 .close = gif_encode_close,
564 .pix_fmts = (const enum AVPixelFormat[]){
565 AV_PIX_FMT_RGB8, AV_PIX_FMT_BGR8, AV_PIX_FMT_RGB4_BYTE, AV_PIX_FMT_BGR4_BYTE,
566 AV_PIX_FMT_GRAY8, AV_PIX_FMT_PAL8, AV_PIX_FMT_NONE
567 },
568 .priv_class = &gif_class,
569 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP,
570 };
571