ffmpeg / libavcodec / gifdec.c @ d36beb3f
History | View | Annotate | Download (9.77 KB)
1 |
/*
|
---|---|
2 |
* GIF decoder
|
3 |
* Copyright (c) 2003 Fabrice Bellard
|
4 |
* Copyright (c) 2006 Baptiste Coudurier
|
5 |
*
|
6 |
* This file is part of FFmpeg.
|
7 |
*
|
8 |
* FFmpeg is free software; you can redistribute it and/or
|
9 |
* modify it under the terms of the GNU Lesser General Public
|
10 |
* License as published by the Free Software Foundation; either
|
11 |
* version 2.1 of the License, or (at your option) any later version.
|
12 |
*
|
13 |
* FFmpeg is distributed in the hope that it will be useful,
|
14 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
16 |
* Lesser General Public License for more details.
|
17 |
*
|
18 |
* You should have received a copy of the GNU Lesser General Public
|
19 |
* License along with FFmpeg; if not, write to the Free Software
|
20 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
21 |
*/
|
22 |
|
23 |
//#define DEBUG
|
24 |
|
25 |
#include "libavcore/imgutils.h" |
26 |
#include "avcodec.h" |
27 |
#include "bytestream.h" |
28 |
#include "lzw.h" |
29 |
|
30 |
#define GCE_DISPOSAL_NONE 0 |
31 |
#define GCE_DISPOSAL_INPLACE 1 |
32 |
#define GCE_DISPOSAL_BACKGROUND 2 |
33 |
#define GCE_DISPOSAL_RESTORE 3 |
34 |
|
35 |
typedef struct GifState { |
36 |
AVFrame picture; |
37 |
int screen_width;
|
38 |
int screen_height;
|
39 |
int bits_per_pixel;
|
40 |
int background_color_index;
|
41 |
int transparent_color_index;
|
42 |
int color_resolution;
|
43 |
uint32_t *image_palette; |
44 |
|
45 |
/* after the frame is displayed, the disposal method is used */
|
46 |
int gce_disposal;
|
47 |
/* delay during which the frame is shown */
|
48 |
int gce_delay;
|
49 |
|
50 |
/* LZW compatible decoder */
|
51 |
const uint8_t *bytestream;
|
52 |
const uint8_t *bytestream_end;
|
53 |
LZWState *lzw; |
54 |
|
55 |
/* aux buffers */
|
56 |
uint8_t global_palette[256 * 3]; |
57 |
uint8_t local_palette[256 * 3]; |
58 |
|
59 |
AVCodecContext* avctx; |
60 |
} GifState; |
61 |
|
62 |
static const uint8_t gif87a_sig[6] = "GIF87a"; |
63 |
static const uint8_t gif89a_sig[6] = "GIF89a"; |
64 |
|
65 |
static int gif_read_image(GifState *s) |
66 |
{ |
67 |
int left, top, width, height, bits_per_pixel, code_size, flags;
|
68 |
int is_interleaved, has_local_palette, y, pass, y1, linesize, n, i;
|
69 |
uint8_t *ptr, *spal, *palette, *ptr1; |
70 |
|
71 |
left = bytestream_get_le16(&s->bytestream); |
72 |
top = bytestream_get_le16(&s->bytestream); |
73 |
width = bytestream_get_le16(&s->bytestream); |
74 |
height = bytestream_get_le16(&s->bytestream); |
75 |
flags = bytestream_get_byte(&s->bytestream); |
76 |
is_interleaved = flags & 0x40;
|
77 |
has_local_palette = flags & 0x80;
|
78 |
bits_per_pixel = (flags & 0x07) + 1; |
79 |
|
80 |
dprintf(s->avctx, "gif: image x=%d y=%d w=%d h=%d\n", left, top, width, height);
|
81 |
|
82 |
if (has_local_palette) {
|
83 |
bytestream_get_buffer(&s->bytestream, s->local_palette, 3 * (1 << bits_per_pixel)); |
84 |
palette = s->local_palette; |
85 |
} else {
|
86 |
palette = s->global_palette; |
87 |
bits_per_pixel = s->bits_per_pixel; |
88 |
} |
89 |
|
90 |
/* verify that all the image is inside the screen dimensions */
|
91 |
if (left + width > s->screen_width ||
|
92 |
top + height > s->screen_height) |
93 |
return AVERROR(EINVAL);
|
94 |
|
95 |
/* build the palette */
|
96 |
n = (1 << bits_per_pixel);
|
97 |
spal = palette; |
98 |
for(i = 0; i < n; i++) { |
99 |
s->image_palette[i] = (0xff << 24) | AV_RB24(spal); |
100 |
spal += 3;
|
101 |
} |
102 |
for(; i < 256; i++) |
103 |
s->image_palette[i] = (0xff << 24); |
104 |
/* handle transparency */
|
105 |
if (s->transparent_color_index >= 0) |
106 |
s->image_palette[s->transparent_color_index] = 0;
|
107 |
|
108 |
/* now get the image data */
|
109 |
code_size = bytestream_get_byte(&s->bytestream); |
110 |
ff_lzw_decode_init(s->lzw, code_size, s->bytestream, |
111 |
s->bytestream_end - s->bytestream, FF_LZW_GIF); |
112 |
|
113 |
/* read all the image */
|
114 |
linesize = s->picture.linesize[0];
|
115 |
ptr1 = s->picture.data[0] + top * linesize + left;
|
116 |
ptr = ptr1; |
117 |
pass = 0;
|
118 |
y1 = 0;
|
119 |
for (y = 0; y < height; y++) { |
120 |
ff_lzw_decode(s->lzw, ptr, width); |
121 |
if (is_interleaved) {
|
122 |
switch(pass) {
|
123 |
default:
|
124 |
case 0: |
125 |
case 1: |
126 |
y1 += 8;
|
127 |
ptr += linesize * 8;
|
128 |
if (y1 >= height) {
|
129 |
y1 = pass ? 2 : 4; |
130 |
ptr = ptr1 + linesize * y1; |
131 |
pass++; |
132 |
} |
133 |
break;
|
134 |
case 2: |
135 |
y1 += 4;
|
136 |
ptr += linesize * 4;
|
137 |
if (y1 >= height) {
|
138 |
y1 = 1;
|
139 |
ptr = ptr1 + linesize; |
140 |
pass++; |
141 |
} |
142 |
break;
|
143 |
case 3: |
144 |
y1 += 2;
|
145 |
ptr += linesize * 2;
|
146 |
break;
|
147 |
} |
148 |
} else {
|
149 |
ptr += linesize; |
150 |
} |
151 |
} |
152 |
/* read the garbage data until end marker is found */
|
153 |
ff_lzw_decode_tail(s->lzw); |
154 |
s->bytestream = ff_lzw_cur_ptr(s->lzw); |
155 |
return 0; |
156 |
} |
157 |
|
158 |
static int gif_read_extension(GifState *s) |
159 |
{ |
160 |
int ext_code, ext_len, i, gce_flags, gce_transparent_index;
|
161 |
|
162 |
/* extension */
|
163 |
ext_code = bytestream_get_byte(&s->bytestream); |
164 |
ext_len = bytestream_get_byte(&s->bytestream); |
165 |
|
166 |
dprintf(s->avctx, "gif: ext_code=0x%x len=%d\n", ext_code, ext_len);
|
167 |
|
168 |
switch(ext_code) {
|
169 |
case 0xf9: |
170 |
if (ext_len != 4) |
171 |
goto discard_ext;
|
172 |
s->transparent_color_index = -1;
|
173 |
gce_flags = bytestream_get_byte(&s->bytestream); |
174 |
s->gce_delay = bytestream_get_le16(&s->bytestream); |
175 |
gce_transparent_index = bytestream_get_byte(&s->bytestream); |
176 |
if (gce_flags & 0x01) |
177 |
s->transparent_color_index = gce_transparent_index; |
178 |
else
|
179 |
s->transparent_color_index = -1;
|
180 |
s->gce_disposal = (gce_flags >> 2) & 0x7; |
181 |
|
182 |
dprintf(s->avctx, "gif: gce_flags=%x delay=%d tcolor=%d disposal=%d\n",
|
183 |
gce_flags, s->gce_delay, |
184 |
s->transparent_color_index, s->gce_disposal); |
185 |
|
186 |
ext_len = bytestream_get_byte(&s->bytestream); |
187 |
break;
|
188 |
} |
189 |
|
190 |
/* NOTE: many extension blocks can come after */
|
191 |
discard_ext:
|
192 |
while (ext_len != 0) { |
193 |
for (i = 0; i < ext_len; i++) |
194 |
bytestream_get_byte(&s->bytestream); |
195 |
ext_len = bytestream_get_byte(&s->bytestream); |
196 |
|
197 |
dprintf(s->avctx, "gif: ext_len1=%d\n", ext_len);
|
198 |
} |
199 |
return 0; |
200 |
} |
201 |
|
202 |
static int gif_read_header1(GifState *s) |
203 |
{ |
204 |
uint8_t sig[6];
|
205 |
int v, n;
|
206 |
int has_global_palette;
|
207 |
|
208 |
if (s->bytestream_end < s->bytestream + 13) |
209 |
return -1; |
210 |
|
211 |
/* read gif signature */
|
212 |
bytestream_get_buffer(&s->bytestream, sig, 6);
|
213 |
if (memcmp(sig, gif87a_sig, 6) != 0 && |
214 |
memcmp(sig, gif89a_sig, 6) != 0) |
215 |
return -1; |
216 |
|
217 |
/* read screen header */
|
218 |
s->transparent_color_index = -1;
|
219 |
s->screen_width = bytestream_get_le16(&s->bytestream); |
220 |
s->screen_height = bytestream_get_le16(&s->bytestream); |
221 |
if( (unsigned)s->screen_width > 32767 |
222 |
|| (unsigned)s->screen_height > 32767){ |
223 |
av_log(NULL, AV_LOG_ERROR, "picture size too large\n"); |
224 |
return -1; |
225 |
} |
226 |
|
227 |
v = bytestream_get_byte(&s->bytestream); |
228 |
s->color_resolution = ((v & 0x70) >> 4) + 1; |
229 |
has_global_palette = (v & 0x80);
|
230 |
s->bits_per_pixel = (v & 0x07) + 1; |
231 |
s->background_color_index = bytestream_get_byte(&s->bytestream); |
232 |
bytestream_get_byte(&s->bytestream); /* ignored */
|
233 |
|
234 |
dprintf(s->avctx, "gif: screen_w=%d screen_h=%d bpp=%d global_palette=%d\n",
|
235 |
s->screen_width, s->screen_height, s->bits_per_pixel, |
236 |
has_global_palette); |
237 |
|
238 |
if (has_global_palette) {
|
239 |
n = 1 << s->bits_per_pixel;
|
240 |
if (s->bytestream_end < s->bytestream + n * 3) |
241 |
return -1; |
242 |
bytestream_get_buffer(&s->bytestream, s->global_palette, n * 3);
|
243 |
} |
244 |
return 0; |
245 |
} |
246 |
|
247 |
static int gif_parse_next_image(GifState *s) |
248 |
{ |
249 |
while (s->bytestream < s->bytestream_end) {
|
250 |
int code = bytestream_get_byte(&s->bytestream);
|
251 |
|
252 |
dprintf(s->avctx, "gif: code=%02x '%c'\n", code, code);
|
253 |
|
254 |
switch (code) {
|
255 |
case ',': |
256 |
return gif_read_image(s);
|
257 |
case '!': |
258 |
if (gif_read_extension(s) < 0) |
259 |
return -1; |
260 |
break;
|
261 |
case ';': |
262 |
/* end of image */
|
263 |
default:
|
264 |
/* error or erroneous EOF */
|
265 |
return -1; |
266 |
} |
267 |
} |
268 |
return -1; |
269 |
} |
270 |
|
271 |
static av_cold int gif_decode_init(AVCodecContext *avctx) |
272 |
{ |
273 |
GifState *s = avctx->priv_data; |
274 |
|
275 |
s->avctx = avctx; |
276 |
|
277 |
avcodec_get_frame_defaults(&s->picture); |
278 |
avctx->coded_frame= &s->picture; |
279 |
s->picture.data[0] = NULL; |
280 |
ff_lzw_decode_open(&s->lzw); |
281 |
return 0; |
282 |
} |
283 |
|
284 |
static int gif_decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPacket *avpkt) |
285 |
{ |
286 |
const uint8_t *buf = avpkt->data;
|
287 |
int buf_size = avpkt->size;
|
288 |
GifState *s = avctx->priv_data; |
289 |
AVFrame *picture = data; |
290 |
int ret;
|
291 |
|
292 |
s->bytestream = buf; |
293 |
s->bytestream_end = buf + buf_size; |
294 |
if (gif_read_header1(s) < 0) |
295 |
return -1; |
296 |
|
297 |
avctx->pix_fmt = PIX_FMT_PAL8; |
298 |
if (av_image_check_size(s->screen_width, s->screen_height, 0, avctx)) |
299 |
return -1; |
300 |
avcodec_set_dimensions(avctx, s->screen_width, s->screen_height); |
301 |
|
302 |
if (s->picture.data[0]) |
303 |
avctx->release_buffer(avctx, &s->picture); |
304 |
if (avctx->get_buffer(avctx, &s->picture) < 0) { |
305 |
av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
|
306 |
return -1; |
307 |
} |
308 |
s->image_palette = (uint32_t *)s->picture.data[1];
|
309 |
ret = gif_parse_next_image(s); |
310 |
if (ret < 0) |
311 |
return ret;
|
312 |
|
313 |
*picture = s->picture; |
314 |
*data_size = sizeof(AVPicture);
|
315 |
return s->bytestream - buf;
|
316 |
} |
317 |
|
318 |
static av_cold int gif_decode_close(AVCodecContext *avctx) |
319 |
{ |
320 |
GifState *s = avctx->priv_data; |
321 |
|
322 |
ff_lzw_decode_close(&s->lzw); |
323 |
if(s->picture.data[0]) |
324 |
avctx->release_buffer(avctx, &s->picture); |
325 |
return 0; |
326 |
} |
327 |
|
328 |
AVCodec ff_gif_decoder = { |
329 |
"gif",
|
330 |
AVMEDIA_TYPE_VIDEO, |
331 |
CODEC_ID_GIF, |
332 |
sizeof(GifState),
|
333 |
gif_decode_init, |
334 |
NULL,
|
335 |
gif_decode_close, |
336 |
gif_decode_frame, |
337 |
CODEC_CAP_DR1, |
338 |
.long_name = NULL_IF_CONFIG_SMALL("GIF (Graphics Interchange Format)"),
|
339 |
}; |