Mercurial > mplayer.hg
annotate libmpdemux/demux_gif.c @ 21901:df67afc568b2
sync tag update
author | voroshil |
---|---|
date | Sun, 14 Jan 2007 06:32:53 +0000 |
parents | b2640a639ac7 |
children | 65b2a9b3bd35 |
rev | line source |
---|---|
9133 | 1 /* |
2 GIF file parser for MPlayer | |
3 by Joey Parrish | |
4 */ | |
5 | |
6 #include <stdio.h> | |
7 #include <stdlib.h> | |
8 #include <unistd.h> | |
9 | |
10 #include "config.h" | |
11 | |
12 #include "mp_msg.h" | |
13 #include "help_mp.h" | |
14 | |
15 #include "stream.h" | |
16 #include "demuxer.h" | |
17 #include "stheader.h" | |
18 | |
19 #include <gif_lib.h> | |
21885 | 20 #include "libvo/fastmemcpy.h" |
21880
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
21 typedef struct { |
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
22 int current_pts; |
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
23 unsigned char *palette; |
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
24 GifFileType *gif; |
21882
68ebac1f2b8d
Fix crash for gif images that have Top or Left set
reimar
parents:
21881
diff
changeset
|
25 int w, h; |
21891 | 26 int useref; |
27 char *refimg; | |
21880
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
28 } gif_priv_t; |
9133 | 29 |
30 #define GIF_SIGNATURE (('G' << 16) | ('I' << 8) | 'F') | |
31 | |
9463
93375ee56629
gif library incompatibility fixes and prefere libungif over libgif. Patch by Joey Parrish <joey@nicewarrior.org>
alex
parents:
9345
diff
changeset
|
32 #ifndef HAVE_GIF_TVT_HACK |
93375ee56629
gif library incompatibility fixes and prefere libungif over libgif. Patch by Joey Parrish <joey@nicewarrior.org>
alex
parents:
9345
diff
changeset
|
33 // not supported by certain versions of the library |
9344
bd7b5078475e
1) codecs.conf changed recently and demux_gif no longer needs to spit
arpi
parents:
9133
diff
changeset
|
34 int my_read_gif(GifFileType *gif, uint8_t *buf, int len) { |
bd7b5078475e
1) codecs.conf changed recently and demux_gif no longer needs to spit
arpi
parents:
9133
diff
changeset
|
35 return stream_read(gif->UserData, buf, len); |
bd7b5078475e
1) codecs.conf changed recently and demux_gif no longer needs to spit
arpi
parents:
9133
diff
changeset
|
36 } |
9463
93375ee56629
gif library incompatibility fixes and prefere libungif over libgif. Patch by Joey Parrish <joey@nicewarrior.org>
alex
parents:
9345
diff
changeset
|
37 #endif |
9344
bd7b5078475e
1) codecs.conf changed recently and demux_gif no longer needs to spit
arpi
parents:
9133
diff
changeset
|
38 |
16175 | 39 static int gif_check_file(demuxer_t *demuxer) |
9133 | 40 { |
41 if (stream_read_int24(demuxer->stream) == GIF_SIGNATURE) | |
16175 | 42 return DEMUXER_TYPE_GIF; |
9133 | 43 return 0; |
44 } | |
45 | |
16175 | 46 static int demux_gif_fill_buffer(demuxer_t *demuxer, demux_stream_t *ds) |
9133 | 47 { |
21880
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
48 gif_priv_t *priv = demuxer->priv; |
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
49 GifFileType *gif = priv->gif; |
9133 | 50 GifRecordType type = UNDEFINED_RECORD_TYPE; |
51 int len = 0; | |
52 demux_packet_t *dp = NULL; | |
53 ColorMapObject *effective_map = NULL; | |
54 char *buf = NULL; | |
21891 | 55 int refmode = 0; |
21895 | 56 int transparency = 0; |
57 uint8_t transparent_col; | |
9133 | 58 |
59 while (type != IMAGE_DESC_RECORD_TYPE) { | |
60 if (DGifGetRecordType(gif, &type) == GIF_ERROR) { | |
61 PrintGifError(); | |
62 return 0; // oops | |
63 } | |
64 if (type == TERMINATE_RECORD_TYPE) | |
65 return 0; // eof | |
66 if (type == SCREEN_DESC_RECORD_TYPE) { | |
67 if (DGifGetScreenDesc(gif) == GIF_ERROR) { | |
68 PrintGifError(); | |
69 return 0; // oops | |
70 } | |
71 } | |
72 if (type == EXTENSION_RECORD_TYPE) { | |
73 int code; | |
74 unsigned char *p = NULL; | |
75 if (DGifGetExtension(gif, &code, &p) == GIF_ERROR) { | |
76 PrintGifError(); | |
77 return 0; // oops | |
78 } | |
79 if (code == 0xF9) { | |
80 int frametime = 0; | |
81 if (p[0] == 4) // is the length correct? | |
21891 | 82 { |
21895 | 83 transparency = p[1] & 1; |
21896 | 84 refmode = (p[1] >> 2) & 3; |
21875
d81cf0be50f0
Frametime was being read from the wrong offset, compare
diego
parents:
18958
diff
changeset
|
85 frametime = (p[3] << 8) | p[2]; // set the time, centiseconds |
21895 | 86 transparent_col = p[4]; |
21891 | 87 } |
21880
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
88 priv->current_pts += frametime; |
9133 | 89 } else if ((code == 0xFE) && (verbose)) { // comment extension |
90 // print iff verbose | |
91 printf("GIF comment: "); | |
92 while (p != NULL) { | |
93 int length = p[0]; | |
94 char *comments = p + 1; | |
95 comments[length] = 0; | |
96 printf("%s", comments); | |
97 if (DGifGetExtensionNext(gif, &p) == GIF_ERROR) { | |
98 PrintGifError(); | |
99 return 0; // oops | |
100 } | |
101 } | |
102 printf("\n"); | |
103 } | |
104 while (p != NULL) { | |
105 if (DGifGetExtensionNext(gif, &p) == GIF_ERROR) { | |
106 PrintGifError(); | |
107 return 0; // oops | |
108 } | |
109 } | |
110 } | |
111 } | |
112 | |
113 if (DGifGetImageDesc(gif) == GIF_ERROR) { | |
114 PrintGifError(); | |
115 return 0; // oops | |
116 } | |
117 | |
118 len = gif->Image.Width * gif->Image.Height; | |
21882
68ebac1f2b8d
Fix crash for gif images that have Top or Left set
reimar
parents:
21881
diff
changeset
|
119 dp = new_demux_packet(priv->w * priv->h); |
21890 | 120 buf = calloc(gif->Image.Width, gif->Image.Height); |
21891 | 121 if (priv->useref) |
122 memcpy(dp->buffer, priv->refimg, priv->w * priv->h); | |
123 else | |
124 memset(dp->buffer, gif->SBackGroundColor, priv->w * priv->h); | |
9133 | 125 |
126 if (DGifGetLine(gif, buf, len) == GIF_ERROR) { | |
127 PrintGifError(); | |
128 return 0; // oops | |
129 } | |
130 | |
131 effective_map = gif->Image.ColorMap; | |
132 if (effective_map == NULL) effective_map = gif->SColorMap; | |
133 | |
134 { | |
135 int y; | |
21883 | 136 int cnt = FFMIN(effective_map->ColorCount, 256); |
21884
7484e767c53d
One more bounds check, though IMO the gif lib really should do this.
reimar
parents:
21883
diff
changeset
|
137 int l = FFMAX(FFMIN(gif->Image.Left, priv->w), 0); |
7484e767c53d
One more bounds check, though IMO the gif lib really should do this.
reimar
parents:
21883
diff
changeset
|
138 int t = FFMAX(FFMIN(gif->Image.Top, priv->h), 0); |
7484e767c53d
One more bounds check, though IMO the gif lib really should do this.
reimar
parents:
21883
diff
changeset
|
139 int w = FFMAX(FFMIN(gif->Image.Width, priv->w - l), 0); |
7484e767c53d
One more bounds check, though IMO the gif lib really should do this.
reimar
parents:
21883
diff
changeset
|
140 int h = FFMAX(FFMIN(gif->Image.Height, priv->h - t), 0); |
21885 | 141 unsigned char *dest = dp->buffer + priv->w * t + l; |
9133 | 142 |
21876 | 143 // copy the palette |
21881
a10888bc9758
Fix invalid read for gifs with a palette for less than 256 colors
reimar
parents:
21880
diff
changeset
|
144 for (y = 0; y < cnt; y++) { |
21893 | 145 priv->palette[(y * 4) + 0] = effective_map->Colors[y].Blue; |
146 priv->palette[(y * 4) + 1] = effective_map->Colors[y].Green; | |
147 priv->palette[(y * 4) + 2] = effective_map->Colors[y].Red; | |
148 priv->palette[(y * 4) + 3] = 0; | |
9133 | 149 } |
150 | |
21895 | 151 if (transparency) { |
152 uint8_t *dpos = dest, *spos = buf; | |
153 int hleft = h; | |
154 while (hleft-- > 0) { | |
155 int wleft = w; | |
156 while (wleft-- > 0) { | |
157 if (*spos != transparent_col) | |
158 *dpos = *spos; | |
159 dpos++; spos++; | |
160 } | |
161 dpos += priv->w - w; | |
162 spos += gif->Image.Width - w; | |
163 } | |
164 } else | |
21896 | 165 memcpy_pic(dest, buf, w, h, priv->w, gif->Image.Width); |
21892 | 166 |
21893 | 167 if (refmode == 1) memcpy(priv->refimg, dp->buffer, priv->w * priv->h); |
21892 | 168 if (refmode == 2 && priv->useref) { |
169 dest = priv->refimg + priv->w * t + l; | |
170 memset(buf, gif->SBackGroundColor, len); | |
171 memcpy_pic(dest, buf, w, h, priv->w, gif->Image.Width); | |
172 } | |
21894 | 173 if (!(refmode & 2)) priv->useref = refmode & 1; |
9133 | 174 } |
175 | |
176 free(buf); | |
177 | |
178 demuxer->video->dpos++; | |
21880
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
179 dp->pts = ((float)priv->current_pts) / 100; |
9133 | 180 dp->pos = stream_tell(demuxer->stream); |
181 ds_add_packet(demuxer->video, dp); | |
182 | |
183 return 1; | |
184 } | |
185 | |
16175 | 186 static demuxer_t* demux_open_gif(demuxer_t* demuxer) |
9133 | 187 { |
21880
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
188 gif_priv_t *priv = calloc(1, sizeof(gif_priv_t)); |
9133 | 189 sh_video_t *sh_video = NULL; |
190 GifFileType *gif = NULL; | |
191 | |
21880
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
192 priv->current_pts = 0; |
9133 | 193 demuxer->seekable = 0; // FIXME |
194 | |
195 // go back to the beginning | |
9345 | 196 stream_seek(demuxer->stream,demuxer->stream->start_pos); |
9133 | 197 |
9463
93375ee56629
gif library incompatibility fixes and prefere libungif over libgif. Patch by Joey Parrish <joey@nicewarrior.org>
alex
parents:
9345
diff
changeset
|
198 #ifdef HAVE_GIF_TVT_HACK |
93375ee56629
gif library incompatibility fixes and prefere libungif over libgif. Patch by Joey Parrish <joey@nicewarrior.org>
alex
parents:
9345
diff
changeset
|
199 // without the TVT functionality of libungif, a hard seek must be |
93375ee56629
gif library incompatibility fixes and prefere libungif over libgif. Patch by Joey Parrish <joey@nicewarrior.org>
alex
parents:
9345
diff
changeset
|
200 // done to the beginning of the file. this is because libgif is |
93375ee56629
gif library incompatibility fixes and prefere libungif over libgif. Patch by Joey Parrish <joey@nicewarrior.org>
alex
parents:
9345
diff
changeset
|
201 // unable to use mplayer's cache, and without this lseek libgif will |
93375ee56629
gif library incompatibility fixes and prefere libungif over libgif. Patch by Joey Parrish <joey@nicewarrior.org>
alex
parents:
9345
diff
changeset
|
202 // not read from the beginning of the file and the command will fail. |
93375ee56629
gif library incompatibility fixes and prefere libungif over libgif. Patch by Joey Parrish <joey@nicewarrior.org>
alex
parents:
9345
diff
changeset
|
203 // with this hack enabled, you will lose the ability to stream a GIF. |
93375ee56629
gif library incompatibility fixes and prefere libungif over libgif. Patch by Joey Parrish <joey@nicewarrior.org>
alex
parents:
9345
diff
changeset
|
204 lseek(demuxer->stream->fd, 0, SEEK_SET); |
93375ee56629
gif library incompatibility fixes and prefere libungif over libgif. Patch by Joey Parrish <joey@nicewarrior.org>
alex
parents:
9345
diff
changeset
|
205 gif = DGifOpenFileHandle(demuxer->stream->fd); |
93375ee56629
gif library incompatibility fixes and prefere libungif over libgif. Patch by Joey Parrish <joey@nicewarrior.org>
alex
parents:
9345
diff
changeset
|
206 #else |
9344
bd7b5078475e
1) codecs.conf changed recently and demux_gif no longer needs to spit
arpi
parents:
9133
diff
changeset
|
207 gif = DGifOpen(demuxer->stream, my_read_gif); |
9463
93375ee56629
gif library incompatibility fixes and prefere libungif over libgif. Patch by Joey Parrish <joey@nicewarrior.org>
alex
parents:
9345
diff
changeset
|
208 #endif |
9133 | 209 if (!gif) { |
210 PrintGifError(); | |
211 return NULL; | |
212 } | |
213 | |
214 // create a new video stream header | |
215 sh_video = new_sh_video(demuxer, 0); | |
216 | |
217 // make sure the demuxer knows about the new video stream header | |
218 // (even though new_sh_video() ought to take care of it) | |
219 demuxer->video->sh = sh_video; | |
220 | |
221 // make sure that the video demuxer stream header knows about its | |
222 // parent video demuxer stream (this is getting wacky), or else | |
223 // video_read_properties() will choke | |
224 sh_video->ds = demuxer->video; | |
225 | |
21887
36cc5a884b6a
Cast SWidth/SHeight to uint16_t, since that's what they actually are.
reimar
parents:
21886
diff
changeset
|
226 sh_video->disp_w = (uint16_t)gif->SWidth; |
36cc5a884b6a
Cast SWidth/SHeight to uint16_t, since that's what they actually are.
reimar
parents:
21886
diff
changeset
|
227 sh_video->disp_h = (uint16_t)gif->SHeight; |
9133 | 228 |
229 sh_video->format = mmioFOURCC(8, 'R', 'G', 'B'); | |
230 | |
231 sh_video->fps = 5.0f; | |
232 sh_video->frametime = 1.0f / sh_video->fps; | |
233 | |
234 sh_video->bih = malloc(sizeof(BITMAPINFOHEADER) + (256 * 4)); | |
235 sh_video->bih->biCompression = sh_video->format; | |
236 sh_video->bih->biBitCount = 8; | |
237 sh_video->bih->biPlanes = 2; | |
21880
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
238 priv->palette = (unsigned char *)(sh_video->bih + 1); |
21882
68ebac1f2b8d
Fix crash for gif images that have Top or Left set
reimar
parents:
21881
diff
changeset
|
239 priv->w = sh_video->disp_w; |
68ebac1f2b8d
Fix crash for gif images that have Top or Left set
reimar
parents:
21881
diff
changeset
|
240 priv->h = sh_video->disp_h; |
21891 | 241 priv->refimg = malloc(priv->w * priv->h); |
9133 | 242 |
21880
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
243 priv->gif = gif; |
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
244 demuxer->priv = priv; |
9133 | 245 |
246 return demuxer; | |
247 } | |
248 | |
16175 | 249 static void demux_close_gif(demuxer_t* demuxer) |
9133 | 250 { |
21880
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
251 gif_priv_t *priv = demuxer->priv; |
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
252 if (!priv) return; |
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
253 if (priv->gif && DGifCloseFile(priv->gif) == GIF_ERROR) |
9133 | 254 PrintGifError(); |
21891 | 255 free(priv->refimg); |
21880
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
256 free(priv); |
9133 | 257 } |
16175 | 258 |
259 | |
260 demuxer_desc_t demuxer_desc_gif = { | |
261 "GIF demuxer", | |
262 "gif", | |
263 "GIF", | |
264 "Joey Parrish", | |
265 "", | |
266 DEMUXER_TYPE_GIF, | |
267 0, // unsafe autodetect | |
268 gif_check_file, | |
269 demux_gif_fill_buffer, | |
270 demux_open_gif, | |
271 demux_close_gif, | |
272 NULL, | |
273 NULL | |
274 }; |