Mercurial > mplayer.hg
annotate libmpdemux/demux_gif.c @ 21894:449b9fb6f67b
Fix: refmodes 2 and 3 leave useref unchanged
author | reimar |
---|---|
date | Sat, 13 Jan 2007 12:46:27 +0000 |
parents | 4a83d090520c |
children | 5d9486bbc156 |
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; |
9133 | 56 |
57 while (type != IMAGE_DESC_RECORD_TYPE) { | |
58 if (DGifGetRecordType(gif, &type) == GIF_ERROR) { | |
59 PrintGifError(); | |
60 return 0; // oops | |
61 } | |
62 if (type == TERMINATE_RECORD_TYPE) | |
63 return 0; // eof | |
64 if (type == SCREEN_DESC_RECORD_TYPE) { | |
65 if (DGifGetScreenDesc(gif) == GIF_ERROR) { | |
66 PrintGifError(); | |
67 return 0; // oops | |
68 } | |
69 } | |
70 if (type == EXTENSION_RECORD_TYPE) { | |
71 int code; | |
72 unsigned char *p = NULL; | |
73 if (DGifGetExtension(gif, &code, &p) == GIF_ERROR) { | |
74 PrintGifError(); | |
75 return 0; // oops | |
76 } | |
77 if (code == 0xF9) { | |
78 int frametime = 0; | |
79 if (p[0] == 4) // is the length correct? | |
21891 | 80 { |
21875
d81cf0be50f0
Frametime was being read from the wrong offset, compare
diego
parents:
18958
diff
changeset
|
81 frametime = (p[3] << 8) | p[2]; // set the time, centiseconds |
21891 | 82 refmode = (p[1] >> 2) & 3; |
83 } | |
21880
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
84 priv->current_pts += frametime; |
9133 | 85 } else if ((code == 0xFE) && (verbose)) { // comment extension |
86 // print iff verbose | |
87 printf("GIF comment: "); | |
88 while (p != NULL) { | |
89 int length = p[0]; | |
90 char *comments = p + 1; | |
91 comments[length] = 0; | |
92 printf("%s", comments); | |
93 if (DGifGetExtensionNext(gif, &p) == GIF_ERROR) { | |
94 PrintGifError(); | |
95 return 0; // oops | |
96 } | |
97 } | |
98 printf("\n"); | |
99 } | |
100 while (p != NULL) { | |
101 if (DGifGetExtensionNext(gif, &p) == GIF_ERROR) { | |
102 PrintGifError(); | |
103 return 0; // oops | |
104 } | |
105 } | |
106 } | |
107 } | |
108 | |
109 if (DGifGetImageDesc(gif) == GIF_ERROR) { | |
110 PrintGifError(); | |
111 return 0; // oops | |
112 } | |
113 | |
114 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
|
115 dp = new_demux_packet(priv->w * priv->h); |
21890 | 116 buf = calloc(gif->Image.Width, gif->Image.Height); |
21891 | 117 if (priv->useref) |
118 memcpy(dp->buffer, priv->refimg, priv->w * priv->h); | |
119 else | |
120 memset(dp->buffer, gif->SBackGroundColor, priv->w * priv->h); | |
9133 | 121 |
122 if (DGifGetLine(gif, buf, len) == GIF_ERROR) { | |
123 PrintGifError(); | |
124 return 0; // oops | |
125 } | |
126 | |
127 effective_map = gif->Image.ColorMap; | |
128 if (effective_map == NULL) effective_map = gif->SColorMap; | |
129 | |
130 { | |
131 int y; | |
21883 | 132 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
|
133 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
|
134 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
|
135 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
|
136 int h = FFMAX(FFMIN(gif->Image.Height, priv->h - t), 0); |
21885 | 137 unsigned char *dest = dp->buffer + priv->w * t + l; |
9133 | 138 |
21876 | 139 // copy the palette |
21881
a10888bc9758
Fix invalid read for gifs with a palette for less than 256 colors
reimar
parents:
21880
diff
changeset
|
140 for (y = 0; y < cnt; y++) { |
21893 | 141 priv->palette[(y * 4) + 0] = effective_map->Colors[y].Blue; |
142 priv->palette[(y * 4) + 1] = effective_map->Colors[y].Green; | |
143 priv->palette[(y * 4) + 2] = effective_map->Colors[y].Red; | |
144 priv->palette[(y * 4) + 3] = 0; | |
9133 | 145 } |
146 | |
21885 | 147 memcpy_pic(dest, buf, w, h, priv->w, gif->Image.Width); |
21892 | 148 |
21893 | 149 if (refmode == 1) memcpy(priv->refimg, dp->buffer, priv->w * priv->h); |
21892 | 150 if (refmode == 2 && priv->useref) { |
151 dest = priv->refimg + priv->w * t + l; | |
152 memset(buf, gif->SBackGroundColor, len); | |
153 memcpy_pic(dest, buf, w, h, priv->w, gif->Image.Width); | |
154 } | |
21894 | 155 if (!(refmode & 2)) priv->useref = refmode & 1; |
9133 | 156 } |
157 | |
158 free(buf); | |
159 | |
160 demuxer->video->dpos++; | |
21880
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
161 dp->pts = ((float)priv->current_pts) / 100; |
9133 | 162 dp->pos = stream_tell(demuxer->stream); |
163 ds_add_packet(demuxer->video, dp); | |
164 | |
165 return 1; | |
166 } | |
167 | |
16175 | 168 static demuxer_t* demux_open_gif(demuxer_t* demuxer) |
9133 | 169 { |
21880
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
170 gif_priv_t *priv = calloc(1, sizeof(gif_priv_t)); |
9133 | 171 sh_video_t *sh_video = NULL; |
172 GifFileType *gif = NULL; | |
173 | |
21880
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
174 priv->current_pts = 0; |
9133 | 175 demuxer->seekable = 0; // FIXME |
176 | |
177 // go back to the beginning | |
9345 | 178 stream_seek(demuxer->stream,demuxer->stream->start_pos); |
9133 | 179 |
9463
93375ee56629
gif library incompatibility fixes and prefere libungif over libgif. Patch by Joey Parrish <joey@nicewarrior.org>
alex
parents:
9345
diff
changeset
|
180 #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
|
181 // 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
|
182 // 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
|
183 // 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
|
184 // 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
|
185 // 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
|
186 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
|
187 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
|
188 #else |
9344
bd7b5078475e
1) codecs.conf changed recently and demux_gif no longer needs to spit
arpi
parents:
9133
diff
changeset
|
189 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
|
190 #endif |
9133 | 191 if (!gif) { |
192 PrintGifError(); | |
193 return NULL; | |
194 } | |
195 | |
196 // create a new video stream header | |
197 sh_video = new_sh_video(demuxer, 0); | |
198 | |
199 // make sure the demuxer knows about the new video stream header | |
200 // (even though new_sh_video() ought to take care of it) | |
201 demuxer->video->sh = sh_video; | |
202 | |
203 // make sure that the video demuxer stream header knows about its | |
204 // parent video demuxer stream (this is getting wacky), or else | |
205 // video_read_properties() will choke | |
206 sh_video->ds = demuxer->video; | |
207 | |
21887
36cc5a884b6a
Cast SWidth/SHeight to uint16_t, since that's what they actually are.
reimar
parents:
21886
diff
changeset
|
208 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
|
209 sh_video->disp_h = (uint16_t)gif->SHeight; |
9133 | 210 |
211 sh_video->format = mmioFOURCC(8, 'R', 'G', 'B'); | |
212 | |
213 sh_video->fps = 5.0f; | |
214 sh_video->frametime = 1.0f / sh_video->fps; | |
215 | |
216 sh_video->bih = malloc(sizeof(BITMAPINFOHEADER) + (256 * 4)); | |
217 sh_video->bih->biCompression = sh_video->format; | |
218 sh_video->bih->biBitCount = 8; | |
219 sh_video->bih->biPlanes = 2; | |
21880
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
220 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
|
221 priv->w = sh_video->disp_w; |
68ebac1f2b8d
Fix crash for gif images that have Top or Left set
reimar
parents:
21881
diff
changeset
|
222 priv->h = sh_video->disp_h; |
21891 | 223 priv->refimg = malloc(priv->w * priv->h); |
9133 | 224 |
21880
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
225 priv->gif = gif; |
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
226 demuxer->priv = priv; |
9133 | 227 |
228 return demuxer; | |
229 } | |
230 | |
16175 | 231 static void demux_close_gif(demuxer_t* demuxer) |
9133 | 232 { |
21880
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
233 gif_priv_t *priv = demuxer->priv; |
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
234 if (!priv) return; |
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
235 if (priv->gif && DGifCloseFile(priv->gif) == GIF_ERROR) |
9133 | 236 PrintGifError(); |
21891 | 237 free(priv->refimg); |
21880
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
238 free(priv); |
9133 | 239 } |
16175 | 240 |
241 | |
242 demuxer_desc_t demuxer_desc_gif = { | |
243 "GIF demuxer", | |
244 "gif", | |
245 "GIF", | |
246 "Joey Parrish", | |
247 "", | |
248 DEMUXER_TYPE_GIF, | |
249 0, // unsafe autodetect | |
250 gif_check_file, | |
251 demux_gif_fill_buffer, | |
252 demux_open_gif, | |
253 demux_close_gif, | |
254 NULL, | |
255 NULL | |
256 }; |