/src/ffmpeg/libavcodec/gifdec.c
Line | Count | Source |
1 | | /* |
2 | | * GIF decoder |
3 | | * Copyright (c) 2003 Fabrice Bellard |
4 | | * Copyright (c) 2006 Baptiste Coudurier |
5 | | * Copyright (c) 2012 Vitaliy E Sugrobov |
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 "libavutil/mem.h" |
25 | | #include "libavutil/opt.h" |
26 | | #include "avcodec.h" |
27 | | #include "bytestream.h" |
28 | | #include "codec_internal.h" |
29 | | #include "decode.h" |
30 | | #include "lzw.h" |
31 | | #include "gif.h" |
32 | | |
33 | | /* This value is intentionally set to "transparent white" color. |
34 | | * It is much better to have white background instead of black |
35 | | * when gif image converted to format which not support transparency. |
36 | | */ |
37 | | #define GIF_TRANSPARENT_COLOR 0x00ffffff |
38 | | |
39 | | typedef struct GifState { |
40 | | const AVClass *class; |
41 | | AVFrame *frame; |
42 | | int screen_width; |
43 | | int screen_height; |
44 | | int has_global_palette; |
45 | | int bits_per_pixel; |
46 | | uint32_t bg_color; |
47 | | int background_color_index; |
48 | | int transparent_color_index; |
49 | | int color_resolution; |
50 | | /* intermediate buffer for storing color indices |
51 | | * obtained from lzw-encoded data stream */ |
52 | | uint8_t *idx_line; |
53 | | int idx_line_size; |
54 | | |
55 | | /* after the frame is displayed, the disposal method is used */ |
56 | | int gce_prev_disposal; |
57 | | int gce_disposal; |
58 | | /* rectangle describing area that must be disposed */ |
59 | | int gce_l, gce_t, gce_w, gce_h; |
60 | | /* depending on disposal method we store either part of the image |
61 | | * drawn on the canvas or background color that |
62 | | * should be used upon disposal */ |
63 | | uint8_t *stored_img; |
64 | | int stored_img_size; |
65 | | int stored_bg_color; |
66 | | |
67 | | GetByteContext gb; |
68 | | LZWState *lzw; |
69 | | |
70 | | /* aux buffers */ |
71 | | uint32_t global_palette[256]; |
72 | | uint32_t local_palette[256]; |
73 | | |
74 | | AVCodecContext *avctx; |
75 | | int keyframe; |
76 | | int keyframe_ok; |
77 | | int trans_color; /**< color value that is used instead of transparent color */ |
78 | | } GifState; |
79 | | |
80 | | static void gif_read_palette(GifState *s, uint32_t *pal, int nb) |
81 | 137k | { |
82 | 137k | int i; |
83 | | |
84 | 573k | for (i = 0; i < nb; i++, pal++) |
85 | 435k | *pal = (0xffu << 24) | bytestream2_get_be24u(&s->gb); |
86 | 137k | } |
87 | | |
88 | | static void gif_fill(AVFrame *picture, uint32_t color) |
89 | 67.2k | { |
90 | 67.2k | const ptrdiff_t linesize = picture->linesize[0]; |
91 | 67.2k | uint8_t *py = picture->data[0]; |
92 | 67.2k | const int w = picture->width; |
93 | 67.2k | const int h = picture->height; |
94 | | |
95 | 28.1M | for (int y = 0; y < h; y++) { |
96 | 28.0M | uint32_t *px = (uint32_t *)py; |
97 | 9.90G | for (int x = 0; x < w; x++) |
98 | 9.87G | px[x] = color; |
99 | 28.0M | py += linesize; |
100 | 28.0M | } |
101 | 67.2k | } |
102 | | |
103 | | static void gif_fill_rect(AVFrame *picture, uint32_t color, int l, int t, int w, int h) |
104 | 551 | { |
105 | 551 | const ptrdiff_t linesize = picture->linesize[0]; |
106 | 551 | uint8_t *py = picture->data[0] + t * linesize; |
107 | | |
108 | 964k | for (int y = 0; y < h; y++) { |
109 | 963k | uint32_t *px = ((uint32_t *)py) + l; |
110 | 19.7M | for (int x = 0; x < w; x++) |
111 | 18.7M | px[x] = color; |
112 | 963k | py += linesize; |
113 | 963k | } |
114 | 551 | } |
115 | | |
116 | | static void gif_copy_img_rect(const uint8_t *src, uint8_t *dst, |
117 | | ptrdiff_t src_linesize, |
118 | | ptrdiff_t dst_linesize, |
119 | | int l, int t, int w, int h) |
120 | 1.90k | { |
121 | 1.90k | const uint8_t *src_py = src; |
122 | 1.90k | uint8_t *dst_py = dst; |
123 | | |
124 | 1.90k | src_py += t * src_linesize; |
125 | 1.90k | dst_py += t * dst_linesize; |
126 | 3.37M | for (int y = 0; y < h; y++) { |
127 | 3.36M | memcpy(dst_py + l * 4, src_py + l * 4, w * 4); |
128 | 3.36M | src_py += src_linesize; |
129 | 3.36M | dst_py += dst_linesize; |
130 | 3.36M | } |
131 | 1.90k | } |
132 | | |
133 | | static int gif_read_image(GifState *s, AVFrame *frame) |
134 | 80.1k | { |
135 | 80.1k | int left, top, width, height, bits_per_pixel, code_size, flags, pw; |
136 | 80.1k | int is_interleaved, has_local_palette, y, pass, y1, pal_size, lzwed_len; |
137 | 80.1k | uint32_t *ptr, *pal, *px, *pr, *ptr1; |
138 | 80.1k | ptrdiff_t linesize; |
139 | 80.1k | int ret; |
140 | 80.1k | uint8_t *idx; |
141 | | |
142 | | /* At least 9 bytes of Image Descriptor. */ |
143 | 80.1k | if (bytestream2_get_bytes_left(&s->gb) < 9) |
144 | 441 | return AVERROR_INVALIDDATA; |
145 | | |
146 | 79.7k | left = bytestream2_get_le16u(&s->gb); |
147 | 79.7k | top = bytestream2_get_le16u(&s->gb); |
148 | 79.7k | width = bytestream2_get_le16u(&s->gb); |
149 | 79.7k | height = bytestream2_get_le16u(&s->gb); |
150 | 79.7k | flags = bytestream2_get_byteu(&s->gb); |
151 | 79.7k | is_interleaved = flags & 0x40; |
152 | 79.7k | has_local_palette = flags & 0x80; |
153 | 79.7k | bits_per_pixel = (flags & 0x07) + 1; |
154 | | |
155 | 79.7k | ff_dlog(s->avctx, "image x=%d y=%d w=%d h=%d\n", left, top, width, height); |
156 | | |
157 | 79.7k | if (has_local_palette) { |
158 | 73.6k | pal_size = 1 << bits_per_pixel; |
159 | | |
160 | 73.6k | if (bytestream2_get_bytes_left(&s->gb) < pal_size * 3) |
161 | 110 | return AVERROR_INVALIDDATA; |
162 | | |
163 | 73.5k | gif_read_palette(s, s->local_palette, pal_size); |
164 | 73.5k | pal = s->local_palette; |
165 | 73.5k | } else { |
166 | 6.04k | if (!s->has_global_palette) { |
167 | 1.48k | av_log(s->avctx, AV_LOG_ERROR, "picture doesn't have either global or local palette.\n"); |
168 | 1.48k | return AVERROR_INVALIDDATA; |
169 | 1.48k | } |
170 | | |
171 | 4.55k | pal = s->global_palette; |
172 | 4.55k | } |
173 | | |
174 | 78.1k | if (s->keyframe) { |
175 | 67.2k | if (s->transparent_color_index == -1 && s->has_global_palette) { |
176 | | /* transparency wasn't set before the first frame, fill with background color */ |
177 | 63.1k | gif_fill(frame, s->bg_color); |
178 | 63.1k | } else { |
179 | | /* otherwise fill with transparent color. |
180 | | * this is necessary since by default picture filled with 0x80808080. */ |
181 | 4.09k | gif_fill(frame, s->trans_color); |
182 | 4.09k | } |
183 | 67.2k | } |
184 | | |
185 | | /* verify that all the image is inside the screen dimensions */ |
186 | 78.1k | if (!width || width > s->screen_width) { |
187 | 74.1k | av_log(s->avctx, AV_LOG_WARNING, "Invalid image width: %d, truncating.\n", width); |
188 | 74.1k | width = s->screen_width; |
189 | 74.1k | } |
190 | 78.1k | if (left >= s->screen_width) { |
191 | 685 | av_log(s->avctx, AV_LOG_ERROR, "Invalid left position: %d.\n", left); |
192 | 685 | return AVERROR_INVALIDDATA; |
193 | 685 | } |
194 | 77.4k | if (!height || height > s->screen_height) { |
195 | 72.6k | av_log(s->avctx, AV_LOG_WARNING, "Invalid image height: %d, truncating.\n", height); |
196 | 72.6k | height = s->screen_height; |
197 | 72.6k | } |
198 | 77.4k | if (top >= s->screen_height) { |
199 | 1.83k | av_log(s->avctx, AV_LOG_ERROR, "Invalid top position: %d.\n", top); |
200 | 1.83k | return AVERROR_INVALIDDATA; |
201 | 1.83k | } |
202 | 75.6k | if (left + width > s->screen_width) { |
203 | | /* width must be kept around to avoid lzw vs line desync */ |
204 | 70.0k | pw = s->screen_width - left; |
205 | 70.0k | av_log(s->avctx, AV_LOG_WARNING, "Image too wide by %d, truncating.\n", |
206 | 70.0k | left + width - s->screen_width); |
207 | 70.0k | } else { |
208 | 5.57k | pw = width; |
209 | 5.57k | } |
210 | 75.6k | if (top + height > s->screen_height) { |
211 | | /* we don't care about the extra invisible lines */ |
212 | 68.4k | av_log(s->avctx, AV_LOG_WARNING, "Image too high by %d, truncating.\n", |
213 | 68.4k | top + height - s->screen_height); |
214 | 68.4k | height = s->screen_height - top; |
215 | 68.4k | } |
216 | | |
217 | | /* process disposal method */ |
218 | 75.6k | if (s->gce_prev_disposal == GCE_DISPOSAL_BACKGROUND) { |
219 | 551 | gif_fill_rect(frame, s->stored_bg_color, s->gce_l, s->gce_t, s->gce_w, s->gce_h); |
220 | 75.0k | } else if (s->gce_prev_disposal == GCE_DISPOSAL_RESTORE) { |
221 | 719 | gif_copy_img_rect(s->stored_img, frame->data[0], |
222 | 719 | FFABS(frame->linesize[0]), frame->linesize[0], s->gce_l, s->gce_t, s->gce_w, s->gce_h); |
223 | 719 | } |
224 | | |
225 | 75.6k | s->gce_prev_disposal = s->gce_disposal; |
226 | | |
227 | 75.6k | if (s->gce_disposal != GCE_DISPOSAL_NONE) { |
228 | 2.33k | s->gce_l = left; s->gce_t = top; |
229 | 2.33k | s->gce_w = pw; s->gce_h = height; |
230 | | |
231 | 2.33k | if (s->gce_disposal == GCE_DISPOSAL_BACKGROUND) { |
232 | 794 | if (s->transparent_color_index >= 0) |
233 | 556 | s->stored_bg_color = s->trans_color; |
234 | 238 | else |
235 | 238 | s->stored_bg_color = s->bg_color; |
236 | 1.53k | } else if (s->gce_disposal == GCE_DISPOSAL_RESTORE) { |
237 | 1.19k | av_fast_malloc(&s->stored_img, &s->stored_img_size, FFABS(frame->linesize[0]) * frame->height); |
238 | 1.19k | if (!s->stored_img) |
239 | 0 | return AVERROR(ENOMEM); |
240 | | |
241 | 1.19k | gif_copy_img_rect(frame->data[0], s->stored_img, |
242 | 1.19k | frame->linesize[0], FFABS(frame->linesize[0]), left, top, pw, height); |
243 | 1.19k | } |
244 | 2.33k | } |
245 | | |
246 | | /* Expect at least 2 bytes: 1 for lzw code size and 1 for block size. */ |
247 | 75.6k | if (bytestream2_get_bytes_left(&s->gb) < 2) |
248 | 311 | return AVERROR_INVALIDDATA; |
249 | | |
250 | | /* now get the image data */ |
251 | 75.2k | code_size = bytestream2_get_byteu(&s->gb); |
252 | 75.2k | if ((ret = ff_lzw_decode_init(s->lzw, code_size, s->gb.buffer, |
253 | 75.2k | bytestream2_get_bytes_left(&s->gb), FF_LZW_GIF)) < 0) { |
254 | 4.26k | av_log(s->avctx, AV_LOG_ERROR, "LZW init failed\n"); |
255 | 4.26k | return ret; |
256 | 4.26k | } |
257 | | |
258 | | /* read all the image */ |
259 | 71.0k | linesize = frame->linesize[0]; |
260 | 71.0k | ptr1 = (uint32_t *)(frame->data[0] + top * linesize) + left; |
261 | 71.0k | ptr = ptr1; |
262 | 71.0k | pass = 0; |
263 | 71.0k | y1 = 0; |
264 | 117k | for (y = 0; y < height; y++) { |
265 | 116k | int count = ff_lzw_decode(s->lzw, s->idx_line, width); |
266 | 116k | if (count != width) { |
267 | 70.4k | if (count) |
268 | 68.6k | av_log(s->avctx, AV_LOG_ERROR, "LZW decode failed\n"); |
269 | 70.4k | goto decode_tail; |
270 | 70.4k | } |
271 | | |
272 | 46.1k | pr = ptr + pw; |
273 | | |
274 | 2.42M | for (px = ptr, idx = s->idx_line; px < pr; px++, idx++) { |
275 | 2.38M | if (*idx != s->transparent_color_index) |
276 | 2.37M | *px = pal[*idx]; |
277 | 2.38M | } |
278 | | |
279 | 46.1k | if (is_interleaved) { |
280 | 12.0k | switch(pass) { |
281 | 0 | default: |
282 | 4.09k | case 0: |
283 | 5.70k | case 1: |
284 | 5.70k | y1 += 8; |
285 | 5.70k | ptr += linesize * 2; |
286 | 5.70k | break; |
287 | 2.77k | case 2: |
288 | 2.77k | y1 += 4; |
289 | 2.77k | ptr += linesize * 1; |
290 | 2.77k | break; |
291 | 3.61k | case 3: |
292 | 3.61k | y1 += 2; |
293 | 3.61k | ptr += linesize / 2; |
294 | 3.61k | break; |
295 | 12.0k | } |
296 | 14.1k | while (y1 >= height) { |
297 | 2.07k | y1 = 4 >> pass; |
298 | 2.07k | ptr = ptr1 + linesize / 4 * y1; |
299 | 2.07k | pass++; |
300 | 2.07k | } |
301 | 34.0k | } else { |
302 | 34.0k | ptr += linesize / 4; |
303 | 34.0k | } |
304 | 46.1k | } |
305 | | |
306 | 71.0k | decode_tail: |
307 | | /* read the garbage data until end marker is found */ |
308 | 71.0k | lzwed_len = ff_lzw_decode_tail(s->lzw); |
309 | 71.0k | bytestream2_skipu(&s->gb, lzwed_len); |
310 | | |
311 | | /* Graphic Control Extension's scope is single frame. |
312 | | * Remove its influence. */ |
313 | 71.0k | s->transparent_color_index = -1; |
314 | 71.0k | s->gce_disposal = GCE_DISPOSAL_NONE; |
315 | | |
316 | 71.0k | return 0; |
317 | 71.0k | } |
318 | | |
319 | | static int gif_read_extension(GifState *s) |
320 | 15.8k | { |
321 | 15.8k | int ext_code, ext_len, gce_flags, gce_transparent_index; |
322 | | |
323 | | /* There must be at least 2 bytes: |
324 | | * 1 for extension label and 1 for extension length. */ |
325 | 15.8k | if (bytestream2_get_bytes_left(&s->gb) < 2) |
326 | 208 | return AVERROR_INVALIDDATA; |
327 | | |
328 | 15.6k | ext_code = bytestream2_get_byteu(&s->gb); |
329 | 15.6k | ext_len = bytestream2_get_byteu(&s->gb); |
330 | | |
331 | 15.6k | ff_dlog(s->avctx, "ext_code=0x%x len=%d\n", ext_code, ext_len); |
332 | | |
333 | 15.6k | switch(ext_code) { |
334 | 2.29k | case GIF_GCE_EXT_LABEL: |
335 | 2.29k | if (ext_len != 4) |
336 | 276 | goto discard_ext; |
337 | | |
338 | | /* We need at least 5 bytes more: 4 is for extension body |
339 | | * and 1 for next block size. */ |
340 | 2.02k | if (bytestream2_get_bytes_left(&s->gb) < 5) |
341 | 458 | return AVERROR_INVALIDDATA; |
342 | | |
343 | 1.56k | gce_flags = bytestream2_get_byteu(&s->gb); |
344 | 1.56k | bytestream2_skipu(&s->gb, 2); // delay during which the frame is shown |
345 | 1.56k | gce_transparent_index = bytestream2_get_byteu(&s->gb); |
346 | 1.56k | if (gce_flags & 0x01) |
347 | 1.14k | s->transparent_color_index = gce_transparent_index; |
348 | 414 | else |
349 | 414 | s->transparent_color_index = -1; |
350 | 1.56k | s->gce_disposal = (gce_flags >> 2) & 0x7; |
351 | | |
352 | 1.56k | ff_dlog(s->avctx, "gce_flags=%x tcolor=%d disposal=%d\n", |
353 | 1.56k | gce_flags, |
354 | 1.56k | s->transparent_color_index, s->gce_disposal); |
355 | | |
356 | 1.56k | if (s->gce_disposal > 3) { |
357 | 376 | s->gce_disposal = GCE_DISPOSAL_NONE; |
358 | 376 | ff_dlog(s->avctx, "invalid value in gce_disposal (%d). Using default value of 0.\n", ext_len); |
359 | 376 | } |
360 | | |
361 | 1.56k | ext_len = bytestream2_get_byteu(&s->gb); |
362 | 1.56k | break; |
363 | 15.6k | } |
364 | | |
365 | | /* NOTE: many extension blocks can come after */ |
366 | 15.1k | discard_ext: |
367 | 23.9k | while (ext_len) { |
368 | | /* There must be at least ext_len bytes and 1 for next block size byte. */ |
369 | 10.1k | if (bytestream2_get_bytes_left(&s->gb) < ext_len + 1) |
370 | 1.33k | return AVERROR_INVALIDDATA; |
371 | | |
372 | 8.80k | bytestream2_skipu(&s->gb, ext_len); |
373 | 8.80k | ext_len = bytestream2_get_byteu(&s->gb); |
374 | | |
375 | 8.80k | ff_dlog(s->avctx, "ext_len1=%d\n", ext_len); |
376 | 8.80k | } |
377 | 13.8k | return 0; |
378 | 15.1k | } |
379 | | |
380 | | static int gif_read_header1(GifState *s) |
381 | 74.1k | { |
382 | 74.1k | uint8_t sig[6]; |
383 | 74.1k | int v, n; |
384 | 74.1k | int background_color_index; |
385 | | |
386 | 74.1k | if (bytestream2_get_bytes_left(&s->gb) < 13) |
387 | 381 | return AVERROR_INVALIDDATA; |
388 | | |
389 | | /* read gif signature */ |
390 | 73.7k | bytestream2_get_bufferu(&s->gb, sig, 6); |
391 | 73.7k | if (memcmp(sig, gif87a_sig, 6) && |
392 | 66.8k | memcmp(sig, gif89a_sig, 6)) |
393 | 0 | return AVERROR_INVALIDDATA; |
394 | | |
395 | | /* read screen header */ |
396 | 73.7k | s->transparent_color_index = -1; |
397 | 73.7k | s->screen_width = bytestream2_get_le16u(&s->gb); |
398 | 73.7k | s->screen_height = bytestream2_get_le16u(&s->gb); |
399 | | |
400 | 73.7k | v = bytestream2_get_byteu(&s->gb); |
401 | 73.7k | s->color_resolution = ((v & 0x70) >> 4) + 1; |
402 | 73.7k | s->has_global_palette = (v & 0x80); |
403 | 73.7k | s->bits_per_pixel = (v & 0x07) + 1; |
404 | 73.7k | background_color_index = bytestream2_get_byteu(&s->gb); |
405 | 73.7k | n = bytestream2_get_byteu(&s->gb); |
406 | 73.7k | if (n) { |
407 | 67.5k | s->avctx->sample_aspect_ratio.num = n + 15; |
408 | 67.5k | s->avctx->sample_aspect_ratio.den = 64; |
409 | 67.5k | } |
410 | | |
411 | 73.7k | ff_dlog(s->avctx, "screen_w=%d screen_h=%d bpp=%d global_palette=%d\n", |
412 | 73.7k | s->screen_width, s->screen_height, s->bits_per_pixel, |
413 | 73.7k | s->has_global_palette); |
414 | | |
415 | 73.7k | if (s->has_global_palette) { |
416 | 64.5k | s->background_color_index = background_color_index; |
417 | 64.5k | n = 1 << s->bits_per_pixel; |
418 | 64.5k | if (bytestream2_get_bytes_left(&s->gb) < n * 3) |
419 | 341 | return AVERROR_INVALIDDATA; |
420 | | |
421 | 64.1k | gif_read_palette(s, s->global_palette, n); |
422 | 64.1k | s->bg_color = s->global_palette[s->background_color_index]; |
423 | 64.1k | } else |
424 | 9.24k | s->background_color_index = -1; |
425 | | |
426 | 73.4k | return 0; |
427 | 73.7k | } |
428 | | |
429 | | static int gif_parse_next_image(GifState *s, AVFrame *frame) |
430 | 110k | { |
431 | 124k | while (bytestream2_get_bytes_left(&s->gb) > 0) { |
432 | 123k | int code = bytestream2_get_byte(&s->gb); |
433 | 123k | int ret; |
434 | | |
435 | 123k | av_log(s->avctx, AV_LOG_DEBUG, "code=%02x '%c'\n", code, code); |
436 | | |
437 | 123k | switch (code) { |
438 | 80.1k | case GIF_IMAGE_SEPARATOR: |
439 | 80.1k | return gif_read_image(s, frame); |
440 | 15.8k | case GIF_EXTENSION_INTRODUCER: |
441 | 15.8k | if ((ret = gif_read_extension(s)) < 0) |
442 | 2.00k | return ret; |
443 | 13.8k | break; |
444 | 13.8k | case GIF_TRAILER: |
445 | | /* end of image */ |
446 | 1.56k | return AVERROR_EOF; |
447 | 26.3k | default: |
448 | | /* erroneous block label */ |
449 | 26.3k | return AVERROR_INVALIDDATA; |
450 | 123k | } |
451 | 123k | } |
452 | 779 | return AVERROR_EOF; |
453 | 110k | } |
454 | | |
455 | | static av_cold int gif_decode_init(AVCodecContext *avctx) |
456 | 2.19k | { |
457 | 2.19k | GifState *s = avctx->priv_data; |
458 | | |
459 | 2.19k | s->avctx = avctx; |
460 | | |
461 | 2.19k | avctx->pix_fmt = AV_PIX_FMT_RGB32; |
462 | 2.19k | s->frame = av_frame_alloc(); |
463 | 2.19k | if (!s->frame) |
464 | 0 | return AVERROR(ENOMEM); |
465 | 2.19k | ff_lzw_decode_open(&s->lzw); |
466 | 2.19k | if (!s->lzw) |
467 | 0 | return AVERROR(ENOMEM); |
468 | 2.19k | return 0; |
469 | 2.19k | } |
470 | | |
471 | | static int gif_decode_frame(AVCodecContext *avctx, AVFrame *rframe, |
472 | | int *got_frame, AVPacket *avpkt) |
473 | 174k | { |
474 | 174k | GifState *s = avctx->priv_data; |
475 | 174k | int ret; |
476 | | |
477 | 174k | bytestream2_init(&s->gb, avpkt->data, avpkt->size); |
478 | | |
479 | 174k | if (avpkt->size >= 6) { |
480 | 109k | s->keyframe = memcmp(avpkt->data, gif87a_sig, 6) == 0 || |
481 | 102k | memcmp(avpkt->data, gif89a_sig, 6) == 0; |
482 | 109k | } else { |
483 | 65.3k | s->keyframe = 0; |
484 | 65.3k | } |
485 | | |
486 | 174k | if (s->keyframe) { |
487 | 74.1k | s->keyframe_ok = 0; |
488 | 74.1k | s->gce_prev_disposal = GCE_DISPOSAL_NONE; |
489 | 74.1k | if ((ret = gif_read_header1(s)) < 0) |
490 | 722 | return ret; |
491 | | |
492 | 73.4k | if ((ret = ff_set_dimensions(avctx, s->screen_width, s->screen_height)) < 0) |
493 | 1.47k | return ret; |
494 | | |
495 | 71.9k | av_frame_unref(s->frame); |
496 | 71.9k | av_fast_malloc(&s->idx_line, &s->idx_line_size, s->screen_width); |
497 | 71.9k | if (!s->idx_line) |
498 | 0 | return AVERROR(ENOMEM); |
499 | 100k | } else if (!s->keyframe_ok) { |
500 | 61.2k | av_log(avctx, AV_LOG_ERROR, "cannot decode frame without keyframe\n"); |
501 | 61.2k | return AVERROR_INVALIDDATA; |
502 | 61.2k | } |
503 | | |
504 | 111k | ret = ff_reget_buffer(avctx, s->frame, 0); |
505 | 111k | if (ret < 0) |
506 | 291 | return ret; |
507 | | |
508 | 110k | ret = gif_parse_next_image(s, s->frame); |
509 | 110k | if (ret < 0) |
510 | 39.8k | return ret; |
511 | | |
512 | 71.0k | if ((ret = av_frame_ref(rframe, s->frame)) < 0) |
513 | 0 | return ret; |
514 | | |
515 | 71.0k | rframe->pict_type = s->keyframe ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P; |
516 | 71.0k | rframe->flags = AV_FRAME_FLAG_KEY * s->keyframe; |
517 | 71.0k | s->keyframe_ok |= !!s->keyframe; |
518 | | |
519 | 71.0k | *got_frame = 1; |
520 | | |
521 | 71.0k | return bytestream2_tell(&s->gb); |
522 | 71.0k | } |
523 | | |
524 | | static av_cold int gif_decode_close(AVCodecContext *avctx) |
525 | 2.19k | { |
526 | 2.19k | GifState *s = avctx->priv_data; |
527 | | |
528 | 2.19k | ff_lzw_decode_close(&s->lzw); |
529 | 2.19k | av_frame_free(&s->frame); |
530 | 2.19k | av_freep(&s->idx_line); |
531 | 2.19k | av_freep(&s->stored_img); |
532 | | |
533 | 2.19k | return 0; |
534 | 2.19k | } |
535 | | |
536 | | static const AVOption options[] = { |
537 | | { "trans_color", "color value (ARGB) that is used instead of transparent color", |
538 | | offsetof(GifState, trans_color), AV_OPT_TYPE_INT, |
539 | | {.i64 = GIF_TRANSPARENT_COLOR}, 0, 0xffffffff, |
540 | | AV_OPT_FLAG_DECODING_PARAM|AV_OPT_FLAG_VIDEO_PARAM }, |
541 | | { NULL }, |
542 | | }; |
543 | | |
544 | | static const AVClass decoder_class = { |
545 | | .class_name = "gif decoder", |
546 | | .item_name = av_default_item_name, |
547 | | .option = options, |
548 | | .version = LIBAVUTIL_VERSION_INT, |
549 | | .category = AV_CLASS_CATEGORY_DECODER, |
550 | | }; |
551 | | |
552 | | const FFCodec ff_gif_decoder = { |
553 | | .p.name = "gif", |
554 | | CODEC_LONG_NAME("GIF (Graphics Interchange Format)"), |
555 | | .p.type = AVMEDIA_TYPE_VIDEO, |
556 | | .p.id = AV_CODEC_ID_GIF, |
557 | | .priv_data_size = sizeof(GifState), |
558 | | .init = gif_decode_init, |
559 | | .close = gif_decode_close, |
560 | | FF_CODEC_DECODE_CB(gif_decode_frame), |
561 | | .p.capabilities = AV_CODEC_CAP_DR1, |
562 | | .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, |
563 | | .p.priv_class = &decoder_class, |
564 | | }; |